General Setup

Setup chunk

Setup reticulate

knitr::opts_chunk$set(fig.width = 8)
knitr::opts_knit$set(root.dir = normalizePath(".."))
knitr::opts_knit$get("root.dir")
[1] "/nas/groups/treutlein/USERS/tomasgomes/projects/liver_regen"

Load libraries

library(reticulate)
knitr::knit_engines$set(python = reticulate::eng_python)
py_available(initialize = FALSE)
[1] FALSE
use_python(Sys.which("python"))
py_config()
python:         /home/tpires/bin/miniconda3/bin/python
libpython:      /home/tpires/bin/miniconda3/lib/libpython3.8.so
pythonhome:     /home/tpires/bin/miniconda3:/home/tpires/bin/miniconda3
version:        3.8.3 (default, May 19 2020, 18:47:26)  [GCC 7.3.0]
numpy:          /home/tpires/bin/miniconda3/lib/python3.8/site-packages/numpy
numpy_version:  1.22.1

NOTE: Python version was forced by RETICULATE_PYTHON

Other functions

library(Seurat)
Attaching SeuratObject
library(ggplot2)
library(plyr)
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:plyr’:

    arrange, count, desc, failwith, id, mutate, rename, summarise, summarize

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(RColorBrewer)

Load data and get markers

Load data

# downsample taking the minimum median of UMI counts as a reference
dsSeurat = function(srat, variable, assay = "SCT", numis = "nCount_SCT", seed = 1){
  # input Seurat object and variable to do the downsample based on
  # return Seurat object
  
  set.seed(seed)
  
  # downsample taking the minimum median of UMI counts as a reference
  fact = srat@meta.data[,numis]/min(tapply(srat@meta.data[,numis], srat@meta.data[,variable], median))
  fact = ifelse(fact<=1, 0, log2(fact))
  thinned_counts = seqgendiff::thin_lib(as.matrix(srat@assays[[assay]]@counts), 
                                        thinlog2 = fact, relative = T)
  rownames(thinned_counts$mat) = rownames(srat@assays[[assay]]@data)
  colnames(thinned_counts$mat) = colnames(srat@assays[[assay]]@data)
  srat@assays$SCT@counts = Matrix::Matrix(thinned_counts$mat, sparse = T)
  srat@assays$SCT@data = log1p(srat@assays[[assay]]@counts)
  
  return(srat)
}

Get downsampled hepatocytes

f = "results/cirrhosis/sub_allcells_css.RDS"
if(!file.exists(f)){
  allcells_css = readRDS(file = "data/processed/allcells_css.RDS")
  end_cells = readRDS(file = "results/endothelial/only_end_cells_zon.RDS")
  hep_cells = readRDS(file = "results/zonation_cond/hep_cells_zonation_rank.RDS")
  imm_cells = readRDS(file = "results/immune/all_imm_cells.RDS")
  
  endpop_df = data.frame(row.names = colnames(end_cells),
                         "subpops" = end_cells@meta.data$endo_simp)
  immpop_df = data.frame(row.names = colnames(imm_cells),
                         "subpops" = imm_cells@meta.data$immune_annot)
  heppop_df = lapply(hep_cells, function(x) cbind(colnames(x), as.character(x$zonation_int)))
  heppop_df = Reduce(rbind, heppop_df)
  heppop_df = data.frame(row.names = heppop_df[,1],
                         subpops = factor(heppop_df[,2]))
  levels(heppop_df$subpops) = c("(-0.00099,0.333]" = "Hepatocytes_Z1",
                                "(0.333,0.667]" = "Hepatocytes_Z2",
                                "(0.667,1]" = "Hepatocytes_Z3")
  heppop_df$subpops = as.character(heppop_df$subpops)
  
  subpop_df = rbind(endpop_df, immpop_df, heppop_df)
  subpop_df$subpops[subpop_df$subpops=="Cycling cells"] = "Dividing endothelial cells"
  
  # add subpop metadata
  allcells_css = AddMetaData(allcells_css, subpop_df)
  allcells_css$subpops[is.na(allcells_css$subpops)] = allcells_css$allcells_major[is.na(allcells_css$subpops)]
  allcells_css$subpops[allcells_css$subpops=="Hepatocyte-Monocyte interaction"] = "Doublets"
  
  # the cells in this object named "Hepatocytes", "Endothelial cells", and "Doublets" have to be removed
  ## the first two are cells that didn't pass the hep and end analysis
  sub_allcells_css = allcells_css[,!(allcells_css$subpops %in% c("Hepatocytes", "Endothelial cells",
                                                                 "Doublets"))]
  allcells_css$subpops[allcells_css$subpops %in% c("Hepatocytes", "Endothelial cells","Doublets")] = "Not annotated"
  
  sub_allcells_css$anno_cond = paste0(sub_allcells_css$subpops, "_", sub_allcells_css$Condition)
  saveRDS(sub_allcells_css, file = f)
} else{
  sub_allcells_css = readRDS(f)
}

Get cell type markers

f = "results/cirrhosis/ds_hep_srat.RDS"
if(!file.exists(f)){
  ds_hep_srat = dsSeurat(sub_allcells_css[,grepl("Hepatoc", sub_allcells_css$subpops)], "Condition")
  saveRDS(ds_hep_srat, file = f)
} else{
  ds_hep_srat = readRDS(f)
}

Load Ramachandran data

cell_type_mk = readRDS(file = "results/cond_effect_v2/cell_type_mk_more.RDS")

Load Camp data

f = "results/cirrhosis/cirr_data_renorm.RDS"
if(!file.exists(f)){
  load("../../data/published/Ramachandran_liver/tissue.rdata")
  
  cirr_data = CreateSeuratObject(counts = tissue@raw.data, meta.data = tissue@meta.data)
  
  # Renormalise, since the original data doesn't look ok
  cirr_data = suppressWarnings(SCTransform(cirr_data, do.correct.umi = T, verbose = F, 
                                           vars.to.regress=c("dataset", "nCount_RNA"),
                                           variable.features.rv.th = 1, seed.use = 1,
                                           return.only.var.genes = F, variable.features.n = NULL))
  
  
  cirr_data$anno_cond = paste0(cirr_data$annotation_indepth, "_", cirr_data$condition)
  saveRDS(cirr_data, file = f)
} else{
  cirr_data = readRDS(f)
}

Get DE genes between conditions

f = "results/cirrhosis/mk_ct_CvsH.RDS"
if(!file.exists(f)){
  cirr_data = SetIdent(cirr_data, value = "annotation_indepth")
  mk_ct_list = list()
  condct = table(cirr_data$annotation_indepth, cirr_data$condition)
  condct = condct[apply(condct, 1, function(x) all(x>=5)),]
  for(ct in rownames(condct)){
    mk_ct_list[[ct]] = FindMarkers(cirr_data, ident.1 = "Cirrhotic", ident.2 = "Uninjured", 
                                   assay = "SCT", group.by = "condition", pseudocount.use = 0.1,
                                   subset.ident = ct)
  }
  saveRDS(mk_ct_list, file = f)
} else{
  mk_ct_list = readRDS(f)
}

f = "results/cirrhosis/mk_li_CvsH.RDS"
if(!file.exists(f)){
  cirr_data = SetIdent(cirr_data, value = "annotation_lineage")
  mk_li_list = list()
  condct = table(cirr_data$annotation_lineage, cirr_data$condition)
  condct = condct[apply(condct, 1, function(x) all(x>=5)),]
  for(ct in rownames(condct)){
    mk_li_list[[ct]] = FindMarkers(cirr_data, ident.1 = "Cirrhotic", ident.2 = "Uninjured", 
                                   assay = "SCT", group.by = "condition", 
                                   pseudocount.use = 0.1, subset.ident = ct)
  }
  saveRDS(mk_li_list, file = f)
} else{
  mk_li_list = readRDS(f)
}

f = "results/cirrhosis/mk_cond.RDS"
if(!file.exists(f)){
  mk_cond = FindMarkers(cirr_data, ident.1 = "Cirrhotic", ident.2 = "Uninjured", assay = "SCT",
                        group.by = "condition", pseudocount.use = 0.1)
  saveRDS(mk_cond, file = f)
} else{
  mk_cond = readRDS(f)
}

Markers for each MPs cell population

f = "results/cirrhosis/mk_ct_CvsH.RDS"
if(!file.exists(f)){
  cirr_data = SetIdent(cirr_data, value = "annotation_indepth")
  mk_ct_list = list()
  condct = table(cirr_data$annotation_indepth, cirr_data$condition)
  condct = condct[apply(condct, 1, function(x) all(x>=5)),]
  for(ct in rownames(condct)){
    mk_ct_list[[ct]] = FindMarkers(cirr_data, ident.1 = "Cirrhotic", ident.2 = "Uninjured", 
                                   assay = "SCT", group.by = "condition", pseudocount.use = 0.1,
                                   subset.ident = ct)
  }
  saveRDS(mk_ct_list, file = f)
} else{
  mk_ct_list = readRDS(f)
}

f = "results/cirrhosis/mk_li_CvsH.RDS"
if(!file.exists(f)){
  cirr_data = SetIdent(cirr_data, value = "annotation_lineage")
  mk_li_list = list()
  condct = table(cirr_data$annotation_lineage, cirr_data$condition)
  condct = condct[apply(condct, 1, function(x) all(x>=5)),]
  for(ct in rownames(condct)){
    mk_li_list[[ct]] = FindMarkers(cirr_data, ident.1 = "Cirrhotic", ident.2 = "Uninjured", 
                                   assay = "SCT", group.by = "condition", 
                                   pseudocount.use = 0.1, subset.ident = ct)
  }
  saveRDS(mk_li_list, file = f)
} else{
  mk_li_list = readRDS(f)
}

f = "results/cirrhosis/mk_cond.RDS"
if(!file.exists(f)){
  mk_cond = FindMarkers(cirr_data, ident.1 = "Cirrhotic", ident.2 = "Uninjured", assay = "SCT",
                        group.by = "condition", pseudocount.use = 0.1)
  saveRDS(mk_cond, file = f)
} else{
  mk_cond = readRDS(f)
}

Markers for each cell population (overall and within compartment)

f = "results/cirrhosis/mk_cirr_mps.RDS"
if(!file.exists(f)){
  cirr_data = SetIdent(cirr_data, value = "annotation_indepth")
  mk_cirr_mps = FindAllMarkers(cirr_data[,grepl("MPs", cirr_data$annotation_indepth)], 
                               assay = "SCT", pseudocount.use = 0.1, only.pos = T, 
                               logfc.threshold = 0.15)
  mk_cirr_mps = mk_cirr_mps[mk_cirr_mps$p_val_adj<=0.05,]
  mk_cirr_mps = mk_cirr_mps[order(mk_cirr_mps$avg_log2FC, decreasing = T),]
  
  saveRDS(mk_cirr_mps, file = f)
} else{
  mk_cirr_mps = readRDS(f)
}

Scoring cirrhotic signatures

Global cirrhotic signature

Scoring global signature

f = "results/cirrhosis/mk_ct_all.RDS"
if(!file.exists(f)){
  mk_ct_all = list()
  for(comp in c("annotation_lineage", "annotation_indepth")){
    cirr_data = SetIdent(cirr_data, value = comp)
    mk_ct = FindAllMarkers(cirr_data, assay = "SCT", pseudocount.use = 0.1, only.pos = T, 
                           logfc.threshold = 0.15)
    mk_ct = mk_ct[mk_ct$p_val_adj<=0.05,]
    mk_ct = mk_ct[order(mk_ct$avg_log2FC, decreasing = T),]
    mk_ct_all[[comp]] = mk_ct
    
    if(comp=="annotation_indepth"){
      l_sub = list()
      for(lin in unique(cirr_data$annotation_lineage)){
        print(lin)
        nct = sum(table(cirr_data$annotation_indepth[cirr_data$annotation_lineage==lin])>0)
        if(nct>1){
          mk_sub = FindAllMarkers(cirr_data[,cirr_data$annotation_lineage==lin], only.pos = T, 
                                  assay = "SCT", pseudocount.use = 0.1, logfc.threshold = 0.3)
          mk_sub = mk_sub[mk_sub$p_val_adj<=0.05,]
          mk_sub = mk_sub[order(mk_sub$avg_log2FC, decreasing = T),]
          l_sub[[lin]] = mk_sub
        }
      }
      mk_ct_all[["perlineage"]] = Reduce(rbind, l_sub)
    }
  }
  saveRDS(mk_ct_all, file = f)
} else{
  mk_ct_all = readRDS(f)
}

Lineage/cell type cirrhotic signature

Scoring by signature determined within lineage (downsamples data to match conditions)

cir_sig_all = list("cirrhotic_all" = rownames(mk_cond)[mk_cond$avg_log2FC>=0.3 & mk_cond$pct.1>0.2 &
                                                         mk_cond$pct.1-mk_cond$pct.2>0.1])

sub_allcells_css = AddModuleScore(sub_allcells_css, features = cir_sig_all, nbin = 20, seed = 1, 
                                  ctrl = 500, name = "cirrhotic_all")

for(lin in unique(sub_allcells_css$allcells_major)){
  ids = unique(sub_allcells_css@active.ident[sub_allcells_css$allcells_major==lin])
  plt = VlnPlot(sub_allcells_css, group.by = "subpops", split.by = "Condition", 
                features = "cirrhotic_all1", idents = ids, ncol = 1)+theme(legend.position = "bottom")
  print(plt)
}
The default behaviour of split.by has changed.
Separate violin plots are now plotted side-by-side.
To restore the old behaviour of a single split violin,
set split.plot = TRUE.
      
This message will be shown once per session.
Warning: Groups with fewer than two data points have been dropped.
Warning: Groups with fewer than two data points have been dropped.
Warning: Groups with fewer than two data points have been dropped.
Warning: Groups with fewer than two data points have been dropped.
Warning: Groups with fewer than two data points have been dropped.
Warning: Groups with fewer than two data points have been dropped.
Warning: Groups with fewer than two data points have been dropped.
Warning: Groups with fewer than two data points have been dropped.
Warning: Groups with fewer than two data points have been dropped.

List, for each cell type, which signatures could make sense

feats = colnames(sub_allcells_dshep@meta.data)[col_sigs]
sig_ass_list = lapply(unique(sub_allcells_dshep@meta.data$subpops), function(x) c())
names(sig_ass_list) = unique(sub_allcells_dshep@meta.data$subpops)
for(ct in names(sig_ass_list)){
  sig_ass_list[[ct]] = c(sig_ass_list[[ct]], "Cirr_li_all")
  if(grepl("NK ", ct) | grepl("Treg", ct) | grepl("ILC", ct) | 
     grepl("T cell", ct) | grepl("MAIT", ct) | grepl("TRM", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("ILCs", feats) | grepl("Tcells", feats)])
  } else if(grepl("DC", ct) | grepl("Kupffer", ct) | grepl("Monocyte", ct) | grepl("Macrophage", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("MPs", feats) | grepl("DC", feats)])
  } else if(grepl("Hepato", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], "Cirr_li_Hepatocytes")
  } else if(grepl("Cholangiocytes", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Cholangiocytes", feats) ])
  } else if(grepl("B cell", ct) | grepl("Plasma", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Bcells", feats)])
  } else if(grepl("Stellate", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Mesenchyme", feats) | grepl("Myofibroblast", feats)])
  } else if(grepl("EC", ct) | grepl("endothelial", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Endothelia", feats)])
  }
}

Testing for significance and individual plotting

feats = colnames(sub_allcells_dshep@meta.data)[col_sigs]
sig_ass_list = lapply(unique(sub_allcells_dshep@meta.data$subpops), function(x) c())
names(sig_ass_list) = unique(sub_allcells_dshep@meta.data$subpops)
for(ct in names(sig_ass_list)){
  sig_ass_list[[ct]] = c(sig_ass_list[[ct]], "Cirr_li_all")
  if(grepl("NK ", ct) | grepl("Treg", ct) | grepl("ILC", ct) | 
     grepl("T cell", ct) | grepl("MAIT", ct) | grepl("TRM", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("ILCs", feats) | grepl("Tcells", feats)])
  } else if(grepl("DC", ct) | grepl("Kupffer", ct) | grepl("Monocyte", ct) | grepl("Macrophage", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("MPs", feats) | grepl("DC", feats)])
  } else if(grepl("Hepato", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], "Cirr_li_Hepatocytes")
  } else if(grepl("Cholangiocytes", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Cholangiocytes", feats) ])
  } else if(grepl("B cell", ct) | grepl("Plasma", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Bcells", feats)])
  } else if(grepl("Stellate", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Mesenchyme", feats) | grepl("Myofibroblast", feats)])
  } else if(grepl("EC", ct) | grepl("endothelial", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Endothelia", feats)])
  }
}

Check top hits

pvaldf_filt = pvaldf[pvaldf$fdr<=0.05,]
sigfc_plts = list()
for(cc in c("healthy_v_embolised", "healthy_v_regenerating")){
  subdf = pvaldf_filt[pvaldf_filt$L3==cc,]
  sigfc_plts[[cc]] = list()
  for(ct in unique(pvaldf_filt$L1)){
    subsubdf = subdf[subdf$L1==ct,]
    subsubdf = subsubdf[order(subsubdf$fc, decreasing = F),]
    subsubdf$L2 = factor(subsubdf$L2, levels = unique(subsubdf$L2))
    
    sigfc_plts[[cc]][[ct]] = ggplot(subsubdf, aes(x = L2, y = fc))+
      geom_col()+
      geom_hline(yintercept = c(-.2, .2), linetype = "dashed")+
      theme_classic()+
      theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1))
  }
}

Cell type signature

Calculate signatures for each cell type

sub_allcells_dshep@meta.data = sub_allcells_dshep@meta.data[,1:118]

# get top markers for cell types
cttop = list()
topn = 50
for(i in unique(mk_ct_all$perlineage$cluster)){
  subdf = mk_ct_all$perlineage[mk_ct_all$perlineage$cluster==i & mk_ct_all$perlineage$p_val_adj<=0.05,]
  cttop[[i]] = subdf[order(subdf$avg_log2FC, decreasing = T),"gene"][1:topn]
  cttop = lapply(cttop, function(x) x[!is.na(x)])
}

# get signatures
sub_allcells_dshep = AddModuleScore(sub_allcells_dshep, features = cttop, nbin = 15, 
                                    seed = 1, ctrl = 500, name = "ct_sig_")
col_sigs = grepl("ct_sig_", colnames(sub_allcells_dshep@meta.data))
colnames(sub_allcells_dshep@meta.data)[col_sigs] = paste0("ct_sig_", names(cttop))

List, for each cell type, which signatures could make sense

feats = colnames(sub_allcells_dshep@meta.data)[startsWith(colnames(sub_allcells_dshep@meta.data), "ct_sig_")]
sig_ass_list = lapply(unique(sub_allcells_dshep@meta.data$subpops), function(x) c())
names(sig_ass_list) = unique(sub_allcells_dshep@meta.data$subpops)
for(ct in names(sig_ass_list)){
  if(grepl("NK ", ct) | grepl("Treg", ct) | grepl("ILC", ct) | 
     grepl("T cell", ct) | grepl("MAIT", ct) | grepl("TRM", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("ILCs", feats) | grepl("Tcells", feats)])
  } else if(grepl("DC", ct) | grepl("Kupffer", ct) | grepl("Monocyte", ct) | grepl("Macrophage", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("MPs", feats) | grepl("DC", feats)])
  } else if(grepl("Hepato", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], "Cirr_li_Hepatocytes")
  } else if(grepl("Cholangiocytes", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Cholangiocytes", feats) ])
  } else if(grepl("B cell", ct) | grepl("Plasma", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Bcells", feats)])
  } else if(grepl("Stellate", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Mesenchyme", feats) | grepl("Myofibroblast", feats)])
  } else if(grepl("EC", ct) | grepl("endothelial", ct)){
    sig_ass_list[[ct]] = c(sig_ass_list[[ct]], feats[grepl("Endothelia", feats)])
  }
}

Plot signatures for groups of cell types

ct_vars = grepl("ct_sig_", colnames(sub_allcells_dshep@meta.data))
plot_df = sub_allcells_dshep@meta.data[,c("subpops", "Condition",
                                          colnames(sub_allcells_dshep@meta.data)[ct_vars])]
plot_df = reshape2::melt(plot_df)

plot_ct_sigs = list()
for(gr in c("Kupffer cells", "CD8 ab-T cells 1", "EC non-LSEC", "Cholangiocytes")){
  ct_use = names(sig_ass_list)[unlist(lapply(sig_ass_list, 
                                    function(x) length(intersect(x,sig_ass_list[[gr]]))==length(x)))]
  sub_plot_df = plot_df[plot_df$subpops %in% ct_use & plot_df$variable %in% sig_ass_list[[gr]],]
  sub_plot_df$variable = substr(sub_plot_df$variable , 8, 200)
  
  mean_df = reshape2::melt(tapply(sub_plot_df$value, sub_plot_df$variable, mean))
  colnames(mean_df)[1] = "variable"
  
  plot_ct_sigs[[gr]] = ggplot(sub_plot_df, aes(x = value, y = subpops, fill = subpops))+
    facet_wrap(~variable, ncol = length(mean_df$variable), scales = "free_x")+
    geom_violin(size = 0.2)+
    geom_vline(mapping = aes(xintercept = value), data = mean_df, linetype = "dashed", size = 0.4)+
    labs(x = "Signature score", y = "Subpopulation")+
    theme_classic()+
    theme(legend.position = "none",
          axis.title = element_text(size = 8),
          axis.text.y = element_text(size = 7, colour = "black"),
          strip.text = element_text(size = 7, colour = "black"),
          axis.text.x = element_text(size = 6.6, colour = "black"))
}

Testing for significance and individual plotting

cond_mat = combn(unique(sub_allcells_dshep$Condition), 2)
pval_list = list()
diff_list = list()
plots_list = list()
for(s in names(sig_ass_list)){
  pval_list[[s]] = list()
  diff_list[[s]] = list()
  plots_list[[s]] = list()
  for(f in sig_ass_list[[s]]){
    pval_list[[s]][[f]] = list()
    diff_list[[s]][[f]] = list()
    plots_list[[s]][[f]] = VlnPlot(sub_allcells_dshep, group.by = "subpops", idents = s, features = f, 
                                     split.by = "Condition", ncol = 1)+theme(legend.position = "bottom")
    # rescaling (not for plotting only testing)
    if(!(paste0(f, "_resc") %in% colnames(sub_allcells_dshep@meta.data))){
      sub_allcells_dshep@meta.data[,paste0(f, "_resc")] = scales::rescale(sub_allcells_dshep@meta.data[,f], 
                                                                          to = c(0, max(scales::rescale(sub_allcells_dshep@meta.data[,f]))))
    }
    for(i in 1:ncol(cond_mat)){
      test = wilcox.test(sub_allcells_dshep@meta.data[sub_allcells_dshep$subpops==s & 
                                                        sub_allcells_dshep$Condition==cond_mat[1,i],paste0(f, "_resc")],
                         sub_allcells_dshep@meta.data[sub_allcells_dshep$subpops==s & 
                                                        sub_allcells_dshep$Condition==cond_mat[2,i],paste0(f, "_resc")], 
                  exact = F)
      id = paste0(cond_mat[1,i], "_v_", cond_mat[2,i])
      pval_list[[s]][[f]][[id]] = test$p.value
      d = mean(sub_allcells_dshep@meta.data[sub_allcells_dshep$subpops==s & 
                                                        sub_allcells_dshep$Condition==cond_mat[1,i],paste0(f, "_resc")])/mean(sub_allcells_dshep@meta.data[sub_allcells_dshep$subpops==s & 
                                                        sub_allcells_dshep$Condition==cond_mat[2,i],paste0(f, "_resc")])
      diff_list[[s]][[f]][[id]] = log2(d)
    }
  }
}

pvaldf_ct = reshape2::melt(pval_list)[,4:1]
pvaldf_ct$fdr = p.adjust(pvaldf_ct$value, method = "fdr")
diffdf_ct = reshape2::melt(diff_list)[,4:1]
pvaldf_ct$fc = diffdf_ct$value

Specific datasets

Calculate cirrhotic signatures

sigs_endo_cond = cir_sigsall[c("Endothelia (1)","Endothelia (2)","Endothelia (3)",
                               "Endothelia (5)","Endothelia (6)", "Endothelia (7)")]
end_cells@meta.data = end_cells@meta.data[,!grepl("cirr_cond_", colnames(end_cells@meta.data))]
end_cells = AddModuleScore(end_cells, features = sigs_endo_cond, nbin = 30, 
                           seed = 1, ctrl = 500, name = "cirr_cond_")
col_sigs = grepl("cirr_cond_", colnames(end_cells@meta.data))
colnames(end_cells@meta.data)[col_sigs] = paste0("cirr_cond_", names(sigs_endo_cond))
colnames(end_cells@meta.data) = gsub(" (", "_", colnames(end_cells@meta.data), fixed = T)
colnames(end_cells@meta.data) = gsub(")", "", colnames(end_cells@meta.data), fixed = T)

sigs_mono_cond = cir_sigsall[c("MPs (1)","MPs (2)","MPs (3)","MPs (4)","MPs (5)","MPs (6)",
                               "MPs (7)","MPs (8)","MPs (9)",
                               "Cycling MPs (1)","Cycling MPs (3)")]
mon_cells@meta.data = mon_cells@meta.data[,!grepl("cirr_cond_", colnames(mon_cells@meta.data))]
mon_cells = AddModuleScore(mon_cells, features = sigs_mono_cond, nbin = 30, 
                           seed = 1, ctrl = 500, name = "cirr_cond_")
col_sigs = grepl("cirr_cond_", colnames(mon_cells@meta.data))
colnames(mon_cells@meta.data)[col_sigs] = paste0("cirr_cond_", names(sigs_mono_cond))
colnames(mon_cells@meta.data) = gsub(" (", "_", colnames(mon_cells@meta.data), fixed = T)
colnames(mon_cells@meta.data) = gsub(")", "", colnames(mon_cells@meta.data), fixed = T)

sigs_hepa_cond = cir_sigsall[c("Hepatocytes")]
ds_hep_srat@meta.data = ds_hep_srat@meta.data[,!grepl("cirr_cond_",
                                                      colnames(ds_hep_srat@meta.data))]
ds_hep_srat = AddModuleScore(ds_hep_srat, features = sigs_hepa_cond, nbin = 30, 
                             seed = 1, ctrl = 500, name = "cirr_cond_")
col_sigs = grepl("cirr_cond_", colnames(ds_hep_srat@meta.data))
colnames(ds_hep_srat@meta.data)[col_sigs] = paste0("cirr_cond_", names(sigs_hepa_cond))

Calculate cell type signatures

sigs_endo_cond = cir_sigsall[c("Endothelia (1)","Endothelia (2)","Endothelia (3)",
                               "Endothelia (5)","Endothelia (6)", "Endothelia (7)")]
end_cells@meta.data = end_cells@meta.data[,!grepl("cirr_cond_", colnames(end_cells@meta.data))]
end_cells = AddModuleScore(end_cells, features = sigs_endo_cond, nbin = 30, 
                           seed = 1, ctrl = 500, name = "cirr_cond_")
col_sigs = grepl("cirr_cond_", colnames(end_cells@meta.data))
colnames(end_cells@meta.data)[col_sigs] = paste0("cirr_cond_", names(sigs_endo_cond))
colnames(end_cells@meta.data) = gsub(" (", "_", colnames(end_cells@meta.data), fixed = T)
colnames(end_cells@meta.data) = gsub(")", "", colnames(end_cells@meta.data), fixed = T)

sigs_mono_cond = cir_sigsall[c("MPs (1)","MPs (2)","MPs (3)","MPs (4)","MPs (5)","MPs (6)",
                               "MPs (7)","MPs (8)","MPs (9)",
                               "Cycling MPs (1)","Cycling MPs (3)")]
mon_cells@meta.data = mon_cells@meta.data[,!grepl("cirr_cond_", colnames(mon_cells@meta.data))]
mon_cells = AddModuleScore(mon_cells, features = sigs_mono_cond, nbin = 30, 
                           seed = 1, ctrl = 500, name = "cirr_cond_")
col_sigs = grepl("cirr_cond_", colnames(mon_cells@meta.data))
colnames(mon_cells@meta.data)[col_sigs] = paste0("cirr_cond_", names(sigs_mono_cond))
colnames(mon_cells@meta.data) = gsub(" (", "_", colnames(mon_cells@meta.data), fixed = T)
colnames(mon_cells@meta.data) = gsub(")", "", colnames(mon_cells@meta.data), fixed = T)

sigs_hepa_cond = cir_sigsall[c("Hepatocytes")]
ds_hep_srat@meta.data = ds_hep_srat@meta.data[,!grepl("cirr_cond_",
                                                      colnames(ds_hep_srat@meta.data))]
ds_hep_srat = AddModuleScore(ds_hep_srat, features = sigs_hepa_cond, nbin = 30, 
                             seed = 1, ctrl = 500, name = "cirr_cond_")
col_sigs = grepl("cirr_cond_", colnames(ds_hep_srat@meta.data))
colnames(ds_hep_srat@meta.data)[col_sigs] = paste0("cirr_cond_", names(sigs_hepa_cond))

Plot signatures - endothelial

sigs_endo_cond = cttop[c("Endothelia (1)","Endothelia (2)","Endothelia (3)","Endothelia (4)",
                         "Endothelia (5)","Endothelia (6)", "Endothelia (7)")]
end_cells@meta.data = end_cells@meta.data[,!grepl("cirr_ct_", colnames(end_cells@meta.data))]
end_cells = AddModuleScore(end_cells, features = sigs_endo_cond, nbin = 30, 
                           seed = 1, ctrl = 500, name = "cirr_ct_")
col_sigs = grepl("cirr_ct_", colnames(end_cells@meta.data))
colnames(end_cells@meta.data)[col_sigs] = paste0("cirr_ct_", names(sigs_endo_cond))
colnames(end_cells@meta.data) = gsub(" (", "_", colnames(end_cells@meta.data), fixed = T)
colnames(end_cells@meta.data) = gsub(")", "", colnames(end_cells@meta.data), fixed = T)

sigs_mono_cond = cttop[c("MPs (1)","MPs (2)","MPs (3)","MPs (4)","MPs (5)","MPs (6)",
                         "MPs (7)","MPs (8)","MPs (9)", "Cycling MPs (1)",
                         "Cycling MPs (2)","Cycling MPs (3)","Cycling MPs (4)")]
mon_cells@meta.data = mon_cells@meta.data[,!grepl("cirr_ct_", colnames(mon_cells@meta.data))]
mon_cells = AddModuleScore(mon_cells, features = sigs_mono_cond, nbin = 30, 
                           seed = 1, ctrl = 500, name = "cirr_ct_")
Warning: The following features are not present in the object: PRRG3, ATXN8OS, not searching for symbol synonyms
col_sigs = grepl("cirr_ct_", colnames(mon_cells@meta.data))
colnames(mon_cells@meta.data)[col_sigs] = paste0("cirr_ct_", names(sigs_mono_cond))
colnames(mon_cells@meta.data) = gsub(" (", "_", colnames(mon_cells@meta.data), fixed = T)
colnames(mon_cells@meta.data) = gsub(")", "", colnames(mon_cells@meta.data), fixed = T)

sigs_hepa_cond = cttop[c("Hepatocytes")]
ds_hep_srat@meta.data = ds_hep_srat@meta.data[,!grepl("cirr_ct_",
                                                      colnames(ds_hep_srat@meta.data))]
ds_hep_srat = AddModuleScore(ds_hep_srat, features = sigs_hepa_cond, nbin = 30, 
                             seed = 1, ctrl = 500, name = "cirr_ct_")
col_sigs = grepl("cirr_ct_", colnames(ds_hep_srat@meta.data))
colnames(ds_hep_srat@meta.data)[col_sigs] = paste0("cirr_ct_", names(sigs_hepa_cond))

Plot signatures - monocytes

VlnPlot(end_cells, group.by = "endo_simp", 
        features = c("cirr_cond_Endothelia_1", "cirr_cond_Endothelia_2",
                     "cirr_cond_Endothelia_3", "cirr_cond_Endothelia_5",
                     "cirr_cond_Endothelia_6", "cirr_cond_Endothelia_7"), 
        split.by = "Condition", ncol = 1)

VlnPlot(end_cells, group.by = "endo_simp", 
        features = c("cirr_ct_Endothelia_1", "cirr_ct_Endothelia_2", "cirr_ct_Endothelia_3",
                     "cirr_ct_Endothelia_4", "cirr_ct_Endothelia_5", "cirr_ct_Endothelia_6",
                     "cirr_ct_Endothelia_7"), 
        split.by = "Condition", ncol = 1)

Plot signatures - hepatocytes

VlnPlot(mon_cells, group.by = "mono_annot", 
        features = c("cirr_cond_MPs_1", "cirr_cond_MPs_2", "cirr_cond_MPs_3", "cirr_cond_MPs_4",
                     "cirr_cond_MPs_5", "cirr_cond_MPs_6","cirr_cond_MPs_7", "cirr_cond_MPs_8",
                     "cirr_cond_MPs_9", "cirr_cond_Cycling MPs_1", "cirr_cond_Cycling MPs_3"), 
        split.by = "Condition", ncol = 1)

VlnPlot(mon_cells, group.by = "mono_annot", 
        features = c("cirr_ct_MPs_1", "cirr_ct_MPs_2", "cirr_ct_MPs_3", "cirr_ct_MPs_4",
                     "cirr_ct_MPs_5", "cirr_ct_MPs_6","cirr_ct_MPs_7", "cirr_ct_MPs_8",
                     "cirr_ct_MPs_9", "cirr_ct_Cycling MPs_1", "cirr_ct_Cycling MPs_2",
                     "cirr_ct_Cycling MPs_3", "cirr_ct_Cycling MPs_4"), 
        split.by = "Condition", ncol = 1)

VlnPlot(ds_hep_srat, group.by = "subpops", features = c("cirr_cond_Hepatocytes"), 
        split.by = "Condition", ncol = 1)

VlnPlot(ds_hep_srat, group.by = "subpops", features = c("cirr_ct_Hepatocytes"), 
        split.by = "Condition", ncol = 1)

Development signature

Get top 100 markers

Calculate gene modules for downsampled hepatocytes

top_de = tapply(top_de$gene, top_de$cluster, c)
Error in split.default(X, group) : first argument must be a vector

Plot signatures

ds_hep_srat@meta.data = ds_hep_srat@meta.data[,!grepl("cirr_fetal_",
                                                      colnames(ds_hep_srat@meta.data))]
ds_hep_srat = AddModuleScore(ds_hep_srat, features = top_de, nbin = 30, 
                             seed = 1, ctrl = 500, name = "cirr_fetal_", assay = "SCT")
Warning: The following features are not present in the object: ACN9, not searching for symbol synonyms
Warning: The following features are not present in the object: C17orf99, HBZ, not searching for symbol synonyms
Warning: The following features are not present in the object: APOC4.APOC2, not searching for symbol synonyms
Warning: The following features are not present in the object: GPR116, PPAP2B, not searching for symbol synonyms
Warning: The following features are not present in the object: APOC4.APOC2, DLK1, NME1.NME2, not searching for symbol synonyms
Warning: The following features are not present in the object: CD97, not searching for symbol synonyms
col_sigs = grepl("cirr_fetal_", colnames(ds_hep_srat@meta.data))
colnames(ds_hep_srat@meta.data)[col_sigs] = paste0("cirr_fetal_", names(top_de))

Plot 2D density

VlnPlot(ds_hep_srat, group.by = "subpops", 
        features = c("cirr_fetal_1","cirr_fetal_2","cirr_fetal_3","cirr_fetal_4",
                     "cirr_fetal_5","cirr_fetal_6", "cirr_fetal_7"), 
        split.by = "Condition", ncol = 1)

Plot density of each variable

ggplot(ds_hep_srat@meta.data, aes(x = cirr_fetal_3, y = cirr_fetal_6, colour = Condition))+
  facet_wrap(~subpops)+
  geom_density_2d()+
  theme_classic()+
  theme(aspect.ratio = 1)

Plot median and quartiles in 2D

plt_adult = ggplot(ds_hep_srat@meta.data, aes(x = cirr_fetal_3, colour = Condition))+
  facet_wrap(~subpops)+
  geom_density()+
  theme_classic()+
  theme(aspect.ratio = 1,
        axis.text = element_text(size = 6, colour = "black"),
        axis.title = element_text(size = 6.5),
        strip.text = element_text(size = 7),
        legend.key.size = unit(0.3, "cm"),
        legend.title = element_text(size = 7),
        legend.text = element_text(size = 6.5),
        legend.position = "none")

plt_fetal = ggplot(ds_hep_srat@meta.data, aes(x = cirr_fetal_6, colour = Condition))+
  facet_wrap(~subpops)+
  geom_density()+
  theme_classic()+
  theme(aspect.ratio = 1,
        axis.text = element_text(size = 6, colour = "black"),
        axis.title = element_text(size = 6.5),
        strip.text = element_text(size = 7),
        legend.key.size = unit(0.3, "cm"),
        legend.title = element_text(size = 7),
        legend.text = element_text(size = 6.5),
        legend.margin = margin(0,0,0,0),
        legend.box.margin = margin(0,0,0,0),
        legend.position = "bottom")

plt_adult/plt_fetal

Save downsampled hep with scores

saveRDS(ds_hep_srat, file = "results/cirrhosis/ds_hep_srat_scoredDev.RDS")
scores_df = ds_hep_srat@meta.data[,c(1:23,33,34,49:55,72:78)]
saveRDS(scores_df, file = "results/cirrhosis/ds_hep_scoredDev_df.RDS")
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCgojIEdlbmVyYWwgU2V0dXAKU2V0dXAgY2h1bmsKCmBgYHtyLCBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aCA9IDgpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gbm9ybWFsaXplUGF0aCgiLi4iKSkKa25pdHI6Om9wdHNfa25pdCRnZXQoInJvb3QuZGlyIikKYGBgCgpTZXR1cCByZXRpY3VsYXRlCgpgYGB7cn0KbGlicmFyeShyZXRpY3VsYXRlKQprbml0cjo6a25pdF9lbmdpbmVzJHNldChweXRob24gPSByZXRpY3VsYXRlOjplbmdfcHl0aG9uKQpweV9hdmFpbGFibGUoaW5pdGlhbGl6ZSA9IEZBTFNFKQp1c2VfcHl0aG9uKFN5cy53aGljaCgicHl0aG9uIikpCnB5X2NvbmZpZygpCmBgYAoKTG9hZCBsaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBseXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpgYGAKCk90aGVyIGZ1bmN0aW9ucwoKYGBge3J9CiMgZG93bnNhbXBsZSB0YWtpbmcgdGhlIG1pbmltdW0gbWVkaWFuIG9mIFVNSSBjb3VudHMgYXMgYSByZWZlcmVuY2UKZHNTZXVyYXQgPSBmdW5jdGlvbihzcmF0LCB2YXJpYWJsZSwgYXNzYXkgPSAiU0NUIiwgbnVtaXMgPSAibkNvdW50X1NDVCIsIHNlZWQgPSAxKXsKICAjIGlucHV0IFNldXJhdCBvYmplY3QgYW5kIHZhcmlhYmxlIHRvIGRvIHRoZSBkb3duc2FtcGxlIGJhc2VkIG9uCiAgIyByZXR1cm4gU2V1cmF0IG9iamVjdAogIAogIHNldC5zZWVkKHNlZWQpCiAgCiAgIyBkb3duc2FtcGxlIHRha2luZyB0aGUgbWluaW11bSBtZWRpYW4gb2YgVU1JIGNvdW50cyBhcyBhIHJlZmVyZW5jZQogIGZhY3QgPSBzcmF0QG1ldGEuZGF0YVssbnVtaXNdL21pbih0YXBwbHkoc3JhdEBtZXRhLmRhdGFbLG51bWlzXSwgc3JhdEBtZXRhLmRhdGFbLHZhcmlhYmxlXSwgbWVkaWFuKSkKICBmYWN0ID0gaWZlbHNlKGZhY3Q8PTEsIDAsIGxvZzIoZmFjdCkpCiAgdGhpbm5lZF9jb3VudHMgPSBzZXFnZW5kaWZmOjp0aGluX2xpYihhcy5tYXRyaXgoc3JhdEBhc3NheXNbW2Fzc2F5XV1AY291bnRzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlubG9nMiA9IGZhY3QsIHJlbGF0aXZlID0gVCkKICByb3duYW1lcyh0aGlubmVkX2NvdW50cyRtYXQpID0gcm93bmFtZXMoc3JhdEBhc3NheXNbW2Fzc2F5XV1AZGF0YSkKICBjb2xuYW1lcyh0aGlubmVkX2NvdW50cyRtYXQpID0gY29sbmFtZXMoc3JhdEBhc3NheXNbW2Fzc2F5XV1AZGF0YSkKICBzcmF0QGFzc2F5cyRTQ1RAY291bnRzID0gTWF0cml4OjpNYXRyaXgodGhpbm5lZF9jb3VudHMkbWF0LCBzcGFyc2UgPSBUKQogIHNyYXRAYXNzYXlzJFNDVEBkYXRhID0gbG9nMXAoc3JhdEBhc3NheXNbW2Fzc2F5XV1AY291bnRzKQogIAogIHJldHVybihzcmF0KQp9CmBgYAoKCgojIExvYWQgZGF0YSBhbmQgZ2V0IG1hcmtlcnMKTG9hZCBkYXRhCgpgYGB7cn0KZiA9ICJyZXN1bHRzL2NpcnJob3Npcy9zdWJfYWxsY2VsbHNfY3NzLlJEUyIKaWYoIWZpbGUuZXhpc3RzKGYpKXsKICBhbGxjZWxsc19jc3MgPSByZWFkUkRTKGZpbGUgPSAiZGF0YS9wcm9jZXNzZWQvYWxsY2VsbHNfY3NzLlJEUyIpCiAgZW5kX2NlbGxzID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvZW5kb3RoZWxpYWwvb25seV9lbmRfY2VsbHNfem9uLlJEUyIpCiAgaGVwX2NlbGxzID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvem9uYXRpb25fY29uZC9oZXBfY2VsbHNfem9uYXRpb25fcmFuay5SRFMiKQogIGltbV9jZWxscyA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2ltbXVuZS9hbGxfaW1tX2NlbGxzLlJEUyIpCiAgCiAgZW5kcG9wX2RmID0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSBjb2xuYW1lcyhlbmRfY2VsbHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgInN1YnBvcHMiID0gZW5kX2NlbGxzQG1ldGEuZGF0YSRlbmRvX3NpbXApCiAgaW1tcG9wX2RmID0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSBjb2xuYW1lcyhpbW1fY2VsbHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgInN1YnBvcHMiID0gaW1tX2NlbGxzQG1ldGEuZGF0YSRpbW11bmVfYW5ub3QpCiAgaGVwcG9wX2RmID0gbGFwcGx5KGhlcF9jZWxscywgZnVuY3Rpb24oeCkgY2JpbmQoY29sbmFtZXMoeCksIGFzLmNoYXJhY3Rlcih4JHpvbmF0aW9uX2ludCkpKQogIGhlcHBvcF9kZiA9IFJlZHVjZShyYmluZCwgaGVwcG9wX2RmKQogIGhlcHBvcF9kZiA9IGRhdGEuZnJhbWUocm93Lm5hbWVzID0gaGVwcG9wX2RmWywxXSwKICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnBvcHMgPSBmYWN0b3IoaGVwcG9wX2RmWywyXSkpCiAgbGV2ZWxzKGhlcHBvcF9kZiRzdWJwb3BzKSA9IGMoIigtMC4wMDA5OSwwLjMzM10iID0gIkhlcGF0b2N5dGVzX1oxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKDAuMzMzLDAuNjY3XSIgPSAiSGVwYXRvY3l0ZXNfWjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIoMC42NjcsMV0iID0gIkhlcGF0b2N5dGVzX1ozIikKICBoZXBwb3BfZGYkc3VicG9wcyA9IGFzLmNoYXJhY3RlcihoZXBwb3BfZGYkc3VicG9wcykKICAKICBzdWJwb3BfZGYgPSByYmluZChlbmRwb3BfZGYsIGltbXBvcF9kZiwgaGVwcG9wX2RmKQogIHN1YnBvcF9kZiRzdWJwb3BzW3N1YnBvcF9kZiRzdWJwb3BzPT0iQ3ljbGluZyBjZWxscyJdID0gIkRpdmlkaW5nIGVuZG90aGVsaWFsIGNlbGxzIgogIAogICMgYWRkIHN1YnBvcCBtZXRhZGF0YQogIGFsbGNlbGxzX2NzcyA9IEFkZE1ldGFEYXRhKGFsbGNlbGxzX2Nzcywgc3VicG9wX2RmKQogIGFsbGNlbGxzX2NzcyRzdWJwb3BzW2lzLm5hKGFsbGNlbGxzX2NzcyRzdWJwb3BzKV0gPSBhbGxjZWxsc19jc3MkYWxsY2VsbHNfbWFqb3JbaXMubmEoYWxsY2VsbHNfY3NzJHN1YnBvcHMpXQogIGFsbGNlbGxzX2NzcyRzdWJwb3BzW2FsbGNlbGxzX2NzcyRzdWJwb3BzPT0iSGVwYXRvY3l0ZS1Nb25vY3l0ZSBpbnRlcmFjdGlvbiJdID0gIkRvdWJsZXRzIgogIAogICMgdGhlIGNlbGxzIGluIHRoaXMgb2JqZWN0IG5hbWVkICJIZXBhdG9jeXRlcyIsICJFbmRvdGhlbGlhbCBjZWxscyIsIGFuZCAiRG91YmxldHMiIGhhdmUgdG8gYmUgcmVtb3ZlZAogICMjIHRoZSBmaXJzdCB0d28gYXJlIGNlbGxzIHRoYXQgZGlkbid0IHBhc3MgdGhlIGhlcCBhbmQgZW5kIGFuYWx5c2lzCiAgc3ViX2FsbGNlbGxzX2NzcyA9IGFsbGNlbGxzX2Nzc1ssIShhbGxjZWxsc19jc3Mkc3VicG9wcyAlaW4lIGMoIkhlcGF0b2N5dGVzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVuZG90aGVsaWFsIGNlbGxzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRvdWJsZXRzIikpXQogIGFsbGNlbGxzX2NzcyRzdWJwb3BzW2FsbGNlbGxzX2NzcyRzdWJwb3BzICVpbiUgYygiSGVwYXRvY3l0ZXMiLCAiRW5kb3RoZWxpYWwgY2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRG91YmxldHMiKV0gPSAiTm90IGFubm90YXRlZCIKICAKICBzdWJfYWxsY2VsbHNfY3NzJGFubm9fY29uZCA9IHBhc3RlMChzdWJfYWxsY2VsbHNfY3NzJHN1YnBvcHMsICJfIiwgc3ViX2FsbGNlbGxzX2NzcyRDb25kaXRpb24pCiAgc2F2ZVJEUyhzdWJfYWxsY2VsbHNfY3NzLCBmaWxlID0gZikKfSBlbHNlewogIHN1Yl9hbGxjZWxsc19jc3MgPSByZWFkUkRTKGYpCiAgZW5kX2NlbGxzID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvZW5kb3RoZWxpYWwvb25seV9lbmRfY2VsbHNfem9uLlJEUyIpCiAgaGVwX2NlbGxzID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvem9uYXRpb25fY29uZC9oZXBfY2VsbHNfem9uYXRpb25fcmFuay5SRFMiKQogIGltbV9jZWxscyA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2ltbXVuZS9hbGxfaW1tX2NlbGxzLlJEUyIpCiAgbW9uX2NlbGxzID0gcmVhZFJEUygicmVzdWx0cy9pbW11bmUvYWxsX21vbl9jZWxscy5SRFMiKQp9CmBgYAoKR2V0IGRvd25zYW1wbGVkIGhlcGF0b2N5dGVzCgpgYGB7cn0KZiA9ICJyZXN1bHRzL2NpcnJob3Npcy9kc19oZXBfc3JhdC5SRFMiCmlmKCFmaWxlLmV4aXN0cyhmKSl7CiAgZHNfaGVwX3NyYXQgPSBkc1NldXJhdChzdWJfYWxsY2VsbHNfY3NzWyxncmVwbCgiSGVwYXRvYyIsIHN1Yl9hbGxjZWxsc19jc3Mkc3VicG9wcyldLCAiQ29uZGl0aW9uIikKICBzYXZlUkRTKGRzX2hlcF9zcmF0LCBmaWxlID0gZikKfSBlbHNlewogIGRzX2hlcF9zcmF0ID0gcmVhZFJEUyhmKQp9CmBgYAoKR2V0IGNlbGwgdHlwZSBtYXJrZXJzCgpgYGB7cn0KY2VsbF90eXBlX21rID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY29uZF9lZmZlY3RfdjIvY2VsbF90eXBlX21rX21vcmUuUkRTIikKYGBgCgpMb2FkIFJhbWFjaGFuZHJhbiBkYXRhCgpgYGB7cn0KZiA9ICJyZXN1bHRzL2NpcnJob3Npcy9jaXJyX2RhdGFfcmVub3JtLlJEUyIKaWYoIWZpbGUuZXhpc3RzKGYpKXsKICBsb2FkKCIuLi8uLi9kYXRhL3B1Ymxpc2hlZC9SYW1hY2hhbmRyYW5fbGl2ZXIvdGlzc3VlLnJkYXRhIikKICAKICBjaXJyX2RhdGEgPSBDcmVhdGVTZXVyYXRPYmplY3QoY291bnRzID0gdGlzc3VlQHJhdy5kYXRhLCBtZXRhLmRhdGEgPSB0aXNzdWVAbWV0YS5kYXRhKQogIAogICMgUmVub3JtYWxpc2UsIHNpbmNlIHRoZSBvcmlnaW5hbCBkYXRhIGRvZXNuJ3QgbG9vayBvawogIGNpcnJfZGF0YSA9IHN1cHByZXNzV2FybmluZ3MoU0NUcmFuc2Zvcm0oY2lycl9kYXRhLCBkby5jb3JyZWN0LnVtaSA9IFQsIHZlcmJvc2UgPSBGLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcnMudG8ucmVncmVzcz1jKCJkYXRhc2V0IiwgIm5Db3VudF9STkEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLmZlYXR1cmVzLnJ2LnRoID0gMSwgc2VlZC51c2UgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuLm9ubHkudmFyLmdlbmVzID0gRiwgdmFyaWFibGUuZmVhdHVyZXMubiA9IE5VTEwpKQogIAogIAogIGNpcnJfZGF0YSRhbm5vX2NvbmQgPSBwYXN0ZTAoY2lycl9kYXRhJGFubm90YXRpb25faW5kZXB0aCwgIl8iLCBjaXJyX2RhdGEkY29uZGl0aW9uKQogIHNhdmVSRFMoY2lycl9kYXRhLCBmaWxlID0gZikKfSBlbHNlewogIGNpcnJfZGF0YSA9IHJlYWRSRFMoZikKfQpgYGAKCkxvYWQgQ2FtcCBkYXRhCgpgYGB7cn0KYmJiID0gcmVhZC5jc3YoIi4uLy4uL2RhdGEvcHVibGlzaGVkL0NhbXBfbGl2ZXIvR1NFOTY5ODFfZGF0YS5odW1hbi5saXZlci5jc3YiLCAKICAgICAgICAgICAgICAgaGVhZGVyID0gVCwgcm93Lm5hbWVzID0gMSkKCmNvdW50cyA9IHQoYmJiWywxMzpuY29sKGJiYildKQptZXRhID0gYmJiWywxOjEyXQpgYGAKCkdldCBERSBnZW5lcyBiZXR3ZWVuIGNvbmRpdGlvbnMKCmBgYHtyfQpmID0gInJlc3VsdHMvY2lycmhvc2lzL21rX2N0X0N2c0guUkRTIgppZighZmlsZS5leGlzdHMoZikpewogIGNpcnJfZGF0YSA9IFNldElkZW50KGNpcnJfZGF0YSwgdmFsdWUgPSAiYW5ub3RhdGlvbl9pbmRlcHRoIikKICBta19jdF9saXN0ID0gbGlzdCgpCiAgY29uZGN0ID0gdGFibGUoY2lycl9kYXRhJGFubm90YXRpb25faW5kZXB0aCwgY2lycl9kYXRhJGNvbmRpdGlvbikKICBjb25kY3QgPSBjb25kY3RbYXBwbHkoY29uZGN0LCAxLCBmdW5jdGlvbih4KSBhbGwoeD49NSkpLF0KICBmb3IoY3QgaW4gcm93bmFtZXMoY29uZGN0KSl7CiAgICBta19jdF9saXN0W1tjdF1dID0gRmluZE1hcmtlcnMoY2lycl9kYXRhLCBpZGVudC4xID0gIkNpcnJob3RpYyIsIGlkZW50LjIgPSAiVW5pbmp1cmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwgZ3JvdXAuYnkgPSAiY29uZGl0aW9uIiwgcHNldWRvY291bnQudXNlID0gMC4xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNldC5pZGVudCA9IGN0KQogIH0KICBzYXZlUkRTKG1rX2N0X2xpc3QsIGZpbGUgPSBmKQp9IGVsc2V7CiAgbWtfY3RfbGlzdCA9IHJlYWRSRFMoZikKfQoKZiA9ICJyZXN1bHRzL2NpcnJob3Npcy9ta19saV9DdnNILlJEUyIKaWYoIWZpbGUuZXhpc3RzKGYpKXsKICBjaXJyX2RhdGEgPSBTZXRJZGVudChjaXJyX2RhdGEsIHZhbHVlID0gImFubm90YXRpb25fbGluZWFnZSIpCiAgbWtfbGlfbGlzdCA9IGxpc3QoKQogIGNvbmRjdCA9IHRhYmxlKGNpcnJfZGF0YSRhbm5vdGF0aW9uX2xpbmVhZ2UsIGNpcnJfZGF0YSRjb25kaXRpb24pCiAgY29uZGN0ID0gY29uZGN0W2FwcGx5KGNvbmRjdCwgMSwgZnVuY3Rpb24oeCkgYWxsKHg+PTUpKSxdCiAgZm9yKGN0IGluIHJvd25hbWVzKGNvbmRjdCkpewogICAgbWtfbGlfbGlzdFtbY3RdXSA9IEZpbmRNYXJrZXJzKGNpcnJfZGF0YSwgaWRlbnQuMSA9ICJDaXJyaG90aWMiLCBpZGVudC4yID0gIlVuaW5qdXJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIsIGdyb3VwLmJ5ID0gImNvbmRpdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzZXVkb2NvdW50LnVzZSA9IDAuMSwgc3Vic2V0LmlkZW50ID0gY3QpCiAgfQogIHNhdmVSRFMobWtfbGlfbGlzdCwgZmlsZSA9IGYpCn0gZWxzZXsKICBta19saV9saXN0ID0gcmVhZFJEUyhmKQp9CgpmID0gInJlc3VsdHMvY2lycmhvc2lzL21rX2NvbmQuUkRTIgppZighZmlsZS5leGlzdHMoZikpewogIG1rX2NvbmQgPSBGaW5kTWFya2VycyhjaXJyX2RhdGEsIGlkZW50LjEgPSAiQ2lycmhvdGljIiwgaWRlbnQuMiA9ICJVbmluanVyZWQiLCBhc3NheSA9ICJTQ1QiLAogICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJjb25kaXRpb24iLCBwc2V1ZG9jb3VudC51c2UgPSAwLjEpCiAgc2F2ZVJEUyhta19jb25kLCBmaWxlID0gZikKfSBlbHNlewogIG1rX2NvbmQgPSByZWFkUkRTKGYpCn0KYGBgCgpNYXJrZXJzIGZvciBlYWNoIE1QcyBjZWxsIHBvcHVsYXRpb24KCmBgYHtyfQpmID0gInJlc3VsdHMvY2lycmhvc2lzL21rX2NpcnJfbXBzLlJEUyIKaWYoIWZpbGUuZXhpc3RzKGYpKXsKICBjaXJyX2RhdGEgPSBTZXRJZGVudChjaXJyX2RhdGEsIHZhbHVlID0gImFubm90YXRpb25faW5kZXB0aCIpCiAgbWtfY2lycl9tcHMgPSBGaW5kQWxsTWFya2VycyhjaXJyX2RhdGFbLGdyZXBsKCJNUHMiLCBjaXJyX2RhdGEkYW5ub3RhdGlvbl9pbmRlcHRoKV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwgcHNldWRvY291bnQudXNlID0gMC4xLCBvbmx5LnBvcyA9IFQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gMC4xNSkKICBta19jaXJyX21wcyA9IG1rX2NpcnJfbXBzW21rX2NpcnJfbXBzJHBfdmFsX2Fkajw9MC4wNSxdCiAgbWtfY2lycl9tcHMgPSBta19jaXJyX21wc1tvcmRlcihta19jaXJyX21wcyRhdmdfbG9nMkZDLCBkZWNyZWFzaW5nID0gVCksXQogIAogIHNhdmVSRFMobWtfY2lycl9tcHMsIGZpbGUgPSBmKQp9IGVsc2V7CiAgbWtfY2lycl9tcHMgPSByZWFkUkRTKGYpCn0KYGBgCgpNYXJrZXJzIGZvciBlYWNoIGNlbGwgcG9wdWxhdGlvbiAob3ZlcmFsbCBhbmQgd2l0aGluIGNvbXBhcnRtZW50KQoKYGBge3J9CmYgPSAicmVzdWx0cy9jaXJyaG9zaXMvbWtfY3RfYWxsLlJEUyIKaWYoIWZpbGUuZXhpc3RzKGYpKXsKICBta19jdF9hbGwgPSBsaXN0KCkKICBmb3IoY29tcCBpbiBjKCJhbm5vdGF0aW9uX2xpbmVhZ2UiLCAiYW5ub3RhdGlvbl9pbmRlcHRoIikpewogICAgY2lycl9kYXRhID0gU2V0SWRlbnQoY2lycl9kYXRhLCB2YWx1ZSA9IGNvbXApCiAgICBta19jdCA9IEZpbmRBbGxNYXJrZXJzKGNpcnJfZGF0YSwgYXNzYXkgPSAiU0NUIiwgcHNldWRvY291bnQudXNlID0gMC4xLCBvbmx5LnBvcyA9IFQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAwLjE1KQogICAgbWtfY3QgPSBta19jdFtta19jdCRwX3ZhbF9hZGo8PTAuMDUsXQogICAgbWtfY3QgPSBta19jdFtvcmRlcihta19jdCRhdmdfbG9nMkZDLCBkZWNyZWFzaW5nID0gVCksXQogICAgbWtfY3RfYWxsW1tjb21wXV0gPSBta19jdAogICAgCiAgICBpZihjb21wPT0iYW5ub3RhdGlvbl9pbmRlcHRoIil7CiAgICAgIGxfc3ViID0gbGlzdCgpCiAgICAgIGZvcihsaW4gaW4gdW5pcXVlKGNpcnJfZGF0YSRhbm5vdGF0aW9uX2xpbmVhZ2UpKXsKICAgICAgICBwcmludChsaW4pCiAgICAgICAgbmN0ID0gc3VtKHRhYmxlKGNpcnJfZGF0YSRhbm5vdGF0aW9uX2luZGVwdGhbY2lycl9kYXRhJGFubm90YXRpb25fbGluZWFnZT09bGluXSk+MCkKICAgICAgICBpZihuY3Q+MSl7CiAgICAgICAgICBta19zdWIgPSBGaW5kQWxsTWFya2VycyhjaXJyX2RhdGFbLGNpcnJfZGF0YSRhbm5vdGF0aW9uX2xpbmVhZ2U9PWxpbl0sIG9ubHkucG9zID0gVCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCBwc2V1ZG9jb3VudC51c2UgPSAwLjEsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMykKICAgICAgICAgIG1rX3N1YiA9IG1rX3N1Yltta19zdWIkcF92YWxfYWRqPD0wLjA1LF0KICAgICAgICAgIG1rX3N1YiA9IG1rX3N1YltvcmRlcihta19zdWIkYXZnX2xvZzJGQywgZGVjcmVhc2luZyA9IFQpLF0KICAgICAgICAgIGxfc3ViW1tsaW5dXSA9IG1rX3N1YgogICAgICAgIH0KICAgICAgfQogICAgICBta19jdF9hbGxbWyJwZXJsaW5lYWdlIl1dID0gUmVkdWNlKHJiaW5kLCBsX3N1YikKICAgIH0KICB9CiAgc2F2ZVJEUyhta19jdF9hbGwsIGZpbGUgPSBmKQp9IGVsc2V7CiAgbWtfY3RfYWxsID0gcmVhZFJEUyhmKQp9CmBgYAoKCgojIFNjb3JpbmcgY2lycmhvdGljIHNpZ25hdHVyZXMKIyMgR2xvYmFsIGNpcnJob3RpYyBzaWduYXR1cmUKU2NvcmluZyBnbG9iYWwgc2lnbmF0dXJlCgpgYGB7ciwgZmlnLndpZHRoPTl9CmNpcl9zaWdfYWxsID0gbGlzdCgiY2lycmhvdGljX2FsbCIgPSByb3duYW1lcyhta19jb25kKVtta19jb25kJGF2Z19sb2cyRkM+PTAuMyAmIG1rX2NvbmQkcGN0LjE+MC4yICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWtfY29uZCRwY3QuMS1ta19jb25kJHBjdC4yPjAuMV0pCgpzdWJfYWxsY2VsbHNfY3NzID0gQWRkTW9kdWxlU2NvcmUoc3ViX2FsbGNlbGxzX2NzcywgZmVhdHVyZXMgPSBjaXJfc2lnX2FsbCwgbmJpbiA9IDIwLCBzZWVkID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdHJsID0gNTAwLCBuYW1lID0gImNpcnJob3RpY19hbGwiKQoKZm9yKGxpbiBpbiB1bmlxdWUoc3ViX2FsbGNlbGxzX2NzcyRhbGxjZWxsc19tYWpvcikpewogIGlkcyA9IHVuaXF1ZShzdWJfYWxsY2VsbHNfY3NzQGFjdGl2ZS5pZGVudFtzdWJfYWxsY2VsbHNfY3NzJGFsbGNlbGxzX21ham9yPT1saW5dKQogIHBsdCA9IFZsblBsb3Qoc3ViX2FsbGNlbGxzX2NzcywgZ3JvdXAuYnkgPSAic3VicG9wcyIsIHNwbGl0LmJ5ID0gIkNvbmRpdGlvbiIsIAogICAgICAgICAgICAgICAgZmVhdHVyZXMgPSAiY2lycmhvdGljX2FsbDEiLCBpZGVudHMgPSBpZHMsIG5jb2wgPSAxKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKICBwcmludChwbHQpCn0KYGBgCgoKIyMgTGluZWFnZS9jZWxsIHR5cGUgY2lycmhvdGljIHNpZ25hdHVyZQpTY29yaW5nIGJ5IHNpZ25hdHVyZSBkZXRlcm1pbmVkIHdpdGhpbiBsaW5lYWdlIChkb3duc2FtcGxlcyBkYXRhIHRvIG1hdGNoIGNvbmRpdGlvbnMpCgpgYGB7ciwgZmlnLndpZHRoPTl9Cm1heGdlbmVzID0gMTAwCiMgZ2V0IHNpZ25hdHVyZSBmb3IgZWFjaCBsaW5lYWdlCmNpcl9zaWdzbGluID0gbGFwcGx5KG1rX2xpX2xpc3QsIGZ1bmN0aW9uKHgpewogIHggPSB4W29yZGVyKHgkYXZnX2xvZzJGQywgZGVjcmVhc2luZyA9IFQpLF0KICByZXR1cm4ocm93bmFtZXMoeClbeCRhdmdfbG9nMkZDPj0wLjMgJiB4JHBjdC4xPjAuMiAmIHgkcGN0LjEteCRwY3QuMj4wLjFdWzE6bWF4Z2VuZXNdKX0pCmNpcl9zaWdzbGluID0gbGFwcGx5KGNpcl9zaWdzbGluLCBmdW5jdGlvbih4KSB4WyFpcy5uYSh4KV0pCgojIGFkZCBtYXJrZXJzIGZvciBjb25kIERFIChpdCB3aWxsIGJlIGZpbHRlcmVkIGJ5IGNlbGwgdHlwZSkKY2lyX3NpZ3NsaW4kb3ZlcmFsbF9maWx0ID0gcm93bmFtZXMobWtfY29uZClbbWtfY29uZCRhdmdfbG9nMkZDPj0wLjMgJiBta19jb25kJHBjdC4xPjAuMiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1rX2NvbmQkcGN0LjEtbWtfY29uZCRwY3QuMj4wLjFdCgojIGFkZCBtYXJrZXJzIGZvciBhbGwgbGluZWFnZXMgKGl0IHdpbGwgYmUgZmlsdGVyZWQgYnkgY2VsbCB0eXBlKQpjaXJfc2lnc2xpbiRhbGxfbGluX2ZpbHQgPSB1bmlxdWUodW5saXN0KGNpcl9zaWdzbGluWzE6MTFdKSkKCiMgZ2V0IHNpZ25hdHVyZSBmb3IgZWFjaCBjZWxsIHR5cGUKY2lyX3NpZ3NjdCA9IGxhcHBseShta19jdF9saXN0LCBmdW5jdGlvbih4KXsKICB4ID0geFtvcmRlcih4JGF2Z19sb2cyRkMsIGRlY3JlYXNpbmcgPSBUKSxdCiAgcmV0dXJuKHJvd25hbWVzKHgpW3gkYXZnX2xvZzJGQz49MC4zICYgeCRwY3QuMT4wLjIgJiB4JHBjdC4xLXgkcGN0LjI+MC4xXVsxOm1heGdlbmVzXSl9KQpjaXJfc2lnc2N0ID0gbGFwcGx5KGNpcl9zaWdzY3QsIGZ1bmN0aW9uKHgpIHhbIWlzLm5hKHgpXSkKCiMgYWRkIG1hcmtlcnMgZm9yIGFsbCBjZWxsIHR5cGVzIChpdCB3aWxsIGJlIGZpbHRlcmVkIGJ5IGNlbGwgdHlwZSkKY2lyX3NpZ3NjdCRhbGxfY3RfZmlsdCA9IHVuaXF1ZSh1bmxpc3QoY2lyX3NpZ3NjdFsxOjQxXSkpCgpjaXJfc2lnc2FsbCA9IGMoY2lyX3NpZ3NsaW4sIGNpcl9zaWdzY3QpCmNpcl9zaWdzYWxsID0gY2lyX3NpZ3NhbGxbIWR1cGxpY2F0ZWQobmFtZXMoY2lyX3NpZ3NhbGwpKV0KCiMgYWRkIG1hcmtlcnMgZm9yIGFsbCBsaW5lYWZlcyBhbmQgY2VsbCB0eXBlcywgZmlsdGVyZWQKY2lyX3NpZ3NhbGwkYWxsX2ZpbHQgPSB1bmlxdWUoYyh1bmxpc3QoY2lyX3NpZ3NjdFsxOjQxXSksIHVubGlzdChjaXJfc2lnc2xpblsxOjExXSkpKQoKIyBnZXQgdG9wIG1hcmtlcnMgZm9yIGNlbGwgdHlwZXMKY3R0b3AgPSBsaXN0KCkKdG9wbiA9IDMwCmZvcihpIGluIHVuaXF1ZShta19jdF9hbGwkcGVybGluZWFnZSRjbHVzdGVyKSl7CiAgc3ViZGYgPSBta19jdF9hbGwkcGVybGluZWFnZVtta19jdF9hbGwkcGVybGluZWFnZSRjbHVzdGVyPT1pICYgbWtfY3RfYWxsJHBlcmxpbmVhZ2UkcF92YWxfYWRqPD0wLjA1LF0KICBjdHRvcFtbaV1dID0gc3ViZGZbb3JkZXIoc3ViZGYkYXZnX2xvZzJGQywgZGVjcmVhc2luZyA9IFQpLCJnZW5lIl1bMTp0b3BuXQogIGN0dG9wID0gbGFwcGx5KGN0dG9wLCBmdW5jdGlvbih4KSB4WyFpcy5uYSh4KV0pCn0KZm9yKGkgaW4gdW5pcXVlKG1rX2N0X2FsbCRhbm5vdGF0aW9uX2luZGVwdGgkY2x1c3RlcikpewogIGlmKCEoaSAlaW4lIG5hbWVzKGN0dG9wKSkpewogICAgc3ViZGYgPSBta19jdF9hbGwkYW5ub3RhdGlvbl9pbmRlcHRoW21rX2N0X2FsbCRhbm5vdGF0aW9uX2luZGVwdGgkY2x1c3Rlcj09aSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBta19jdF9hbGwkYW5ub3RhdGlvbl9pbmRlcHRoJHBfdmFsX2Fkajw9MC4wNSxdCiAgICBjdHRvcFtbaV1dID0gc3ViZGZbb3JkZXIoc3ViZGYkYXZnX2xvZzJGQywgZGVjcmVhc2luZyA9IFQpLCJnZW5lIl1bMTp0b3BuXQogICAgY3R0b3AgPSBsYXBwbHkoY3R0b3AsIGZ1bmN0aW9uKHgpIHhbIWlzLm5hKHgpXSkKICB9Cn0KIyBmaWx0ZXIgb3V0IG1hcmtlciBnZW5lcyBmb3IgaW5kaXZpZHVhbCBjZWxsIHR5cGVzCmNpcl9zaWdzYWxsX2ZpbHQgPSBsaXN0KCkKZm9yKG4gaW4gbmFtZXMoY2lyX3NpZ3NhbGwpKXsKICBjaXJfc2lnc2FsbF9maWx0W1tuXV0gPSBjaXJfc2lnc2FsbFtbbl1dWyEoY2lyX3NpZ3NhbGxbW25dXSAlaW4lIHVubGlzdChjdHRvcCkpXQp9CgojIGFkZCBvdmVyYWxsIHNpZ25hdHVyZSAodW5maWx0ZXJlZCkKY2lyX3NpZ3NhbGwkb3ZlcmFsbCA9IHJvd25hbWVzKG1rX2NvbmQpW21rX2NvbmQkYXZnX2xvZzJGQz49MC4zICYgbWtfY29uZCRwY3QuMT4wLjIgJiBta19jb25kJHBjdC4xLW1rX2NvbmQkcGN0LjI+MC4xXQoKIyBhZGQgbWFya2VycyBmb3IgYWxsIGxpbmVhZ2VzIGFuZC9vciBjZWxsIHR5cGVzICh1bmZpbHRlcmVkKQpjaXJfc2lnc2FsbCRhbGxfY3QgPSB1bmlxdWUodW5saXN0KGNpcl9zaWdzY3RbMTo0MV0pKQpjaXJfc2lnc2FsbCRhbGxfbGluID0gdW5pcXVlKHVubGlzdChjaXJfc2lnc2xpblsxOjExXSkpCmNpcl9zaWdzYWxsJGFsbCA9IHVuaXF1ZShjKHVubGlzdChjaXJfc2lnc2N0WzE6NDFdKSwgdW5saXN0KGNpcl9zaWdzbGluWzE6MTFdKSkpCgojIGFkZCBkb3duc2FtcGxlZCBIZXBhdG9jeXRlcyB0byBkYXRhCnN1Yl9hbGxjZWxsc19kc2hlcCA9IHN1Yl9hbGxjZWxsc19jc3NbLCEoY29sbmFtZXMoc3ViX2FsbGNlbGxzX2NzcykgJWluJSBjb2xuYW1lcyhkc19oZXBfc3JhdCkpXQpzdWJfYWxsY2VsbHNfZHNoZXAgPSBtZXJnZShzdWJfYWxsY2VsbHNfZHNoZXAsIGRzX2hlcF9zcmF0KQpzdWJfYWxsY2VsbHNfZHNoZXAgPSBTZXRJZGVudChzdWJfYWxsY2VsbHNfZHNoZXAsIHZhbHVlID0gInN1YnBvcHMiKQoKIyBnZXQgc2lnbmF0dXJlcwpzdWJfYWxsY2VsbHNfZHNoZXAgPSBBZGRNb2R1bGVTY29yZShzdWJfYWxsY2VsbHNfZHNoZXAsIGZlYXR1cmVzID0gY2lyX3NpZ3NhbGxfZmlsdCwgbmJpbiA9IDMwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9IDEsIGN0cmwgPSA1MDAsIG5hbWUgPSAiQ2lycl9saV8iKQpjb2xfc2lncyA9IGdyZXBsKCJDaXJyX2xpXyIsIGNvbG5hbWVzKHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGEpKQpjb2xuYW1lcyhzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhKVtjb2xfc2lnc10gPSBwYXN0ZTAoIkNpcnJfbGlfIiwgbmFtZXMoY2lyX3NpZ3NhbGxfZmlsdCkpCgpjb25kID0gc3RhcnRzV2l0aChjb2xuYW1lcyhzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhKSwgIkNpcnJfbGkiKQpmb3IoY2MgaW4gY29sbmFtZXMoc3ViX2FsbGNlbGxzX2RzaGVwQG1ldGEuZGF0YSlbY29uZF0pewogIGNvbmQyID0gaXMubmEoc3ViX2FsbGNlbGxzX2RzaGVwQG1ldGEuZGF0YVssY2NdKQogIHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGFbLGNjXVtjb25kMl0gPSBtaW4oc3ViX2FsbGNlbGxzX2RzaGVwQG1ldGEuZGF0YVssY2NdWyFjb25kMl0pLTAuMQp9CmBgYAoKTGlzdCwgZm9yIGVhY2ggY2VsbCB0eXBlLCB3aGljaCBzaWduYXR1cmVzIGNvdWxkIG1ha2Ugc2Vuc2UKCmBgYHtyfQpmZWF0cyA9IGNvbG5hbWVzKHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGEpW2NvbF9zaWdzXQpzaWdfYXNzX2xpc3QgPSBsYXBwbHkodW5pcXVlKHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGEkc3VicG9wcyksIGZ1bmN0aW9uKHgpIGMoKSkKbmFtZXMoc2lnX2Fzc19saXN0KSA9IHVuaXF1ZShzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhJHN1YnBvcHMpCmZvcihjdCBpbiBuYW1lcyhzaWdfYXNzX2xpc3QpKXsKICBzaWdfYXNzX2xpc3RbW2N0XV0gPSBjKHNpZ19hc3NfbGlzdFtbY3RdXSwgIkNpcnJfbGlfYWxsIikKICBpZihncmVwbCgiTksgIiwgY3QpIHwgZ3JlcGwoIlRyZWciLCBjdCkgfCBncmVwbCgiSUxDIiwgY3QpIHwgCiAgICAgZ3JlcGwoIlQgY2VsbCIsIGN0KSB8IGdyZXBsKCJNQUlUIiwgY3QpIHwgZ3JlcGwoIlRSTSIsIGN0KSl7CiAgICBzaWdfYXNzX2xpc3RbW2N0XV0gPSBjKHNpZ19hc3NfbGlzdFtbY3RdXSwgZmVhdHNbZ3JlcGwoIklMQ3MiLCBmZWF0cykgfCBncmVwbCgiVGNlbGxzIiwgZmVhdHMpXSkKICB9IGVsc2UgaWYoZ3JlcGwoIkRDIiwgY3QpIHwgZ3JlcGwoIkt1cGZmZXIiLCBjdCkgfCBncmVwbCgiTW9ub2N5dGUiLCBjdCkgfCBncmVwbCgiTWFjcm9waGFnZSIsIGN0KSl7CiAgICBzaWdfYXNzX2xpc3RbW2N0XV0gPSBjKHNpZ19hc3NfbGlzdFtbY3RdXSwgZmVhdHNbZ3JlcGwoIk1QcyIsIGZlYXRzKSB8IGdyZXBsKCJEQyIsIGZlYXRzKV0pCiAgfSBlbHNlIGlmKGdyZXBsKCJIZXBhdG8iLCBjdCkpewogICAgc2lnX2Fzc19saXN0W1tjdF1dID0gYyhzaWdfYXNzX2xpc3RbW2N0XV0sICJDaXJyX2xpX0hlcGF0b2N5dGVzIikKICB9IGVsc2UgaWYoZ3JlcGwoIkNob2xhbmdpb2N5dGVzIiwgY3QpKXsKICAgIHNpZ19hc3NfbGlzdFtbY3RdXSA9IGMoc2lnX2Fzc19saXN0W1tjdF1dLCBmZWF0c1tncmVwbCgiQ2hvbGFuZ2lvY3l0ZXMiLCBmZWF0cykgXSkKICB9IGVsc2UgaWYoZ3JlcGwoIkIgY2VsbCIsIGN0KSB8IGdyZXBsKCJQbGFzbWEiLCBjdCkpewogICAgc2lnX2Fzc19saXN0W1tjdF1dID0gYyhzaWdfYXNzX2xpc3RbW2N0XV0sIGZlYXRzW2dyZXBsKCJCY2VsbHMiLCBmZWF0cyldKQogIH0gZWxzZSBpZihncmVwbCgiU3RlbGxhdGUiLCBjdCkpewogICAgc2lnX2Fzc19saXN0W1tjdF1dID0gYyhzaWdfYXNzX2xpc3RbW2N0XV0sIGZlYXRzW2dyZXBsKCJNZXNlbmNoeW1lIiwgZmVhdHMpIHwgZ3JlcGwoIk15b2ZpYnJvYmxhc3QiLCBmZWF0cyldKQogIH0gZWxzZSBpZihncmVwbCgiRUMiLCBjdCkgfCBncmVwbCgiZW5kb3RoZWxpYWwiLCBjdCkpewogICAgc2lnX2Fzc19saXN0W1tjdF1dID0gYyhzaWdfYXNzX2xpc3RbW2N0XV0sIGZlYXRzW2dyZXBsKCJFbmRvdGhlbGlhIiwgZmVhdHMpXSkKICB9Cn0KYGBgCgpUZXN0aW5nIGZvciBzaWduaWZpY2FuY2UgYW5kIGluZGl2aWR1YWwgcGxvdHRpbmcKCmBgYHtyfQpjb25kX21hdCA9IGNvbWJuKHVuaXF1ZShzdWJfYWxsY2VsbHNfZHNoZXAkQ29uZGl0aW9uKSwgMikKcHZhbF9saXN0ID0gbGlzdCgpCmRpZmZfbGlzdCA9IGxpc3QoKQpwbG90c19saXN0ID0gbGlzdCgpCmZvcihzIGluIG5hbWVzKHNpZ19hc3NfbGlzdCkpewogIHB2YWxfbGlzdFtbc11dID0gbGlzdCgpCiAgZGlmZl9saXN0W1tzXV0gPSBsaXN0KCkKICBwbG90c19saXN0W1tzXV0gPSBsaXN0KCkKICBmb3IoZiBpbiBzaWdfYXNzX2xpc3RbW3NdXSl7CiAgICBwdmFsX2xpc3RbW3NdXVtbZl1dID0gbGlzdCgpCiAgICBkaWZmX2xpc3RbW3NdXVtbZl1dID0gbGlzdCgpCiAgICBwbG90c19saXN0W1tzXV1bW2ZdXSA9IFZsblBsb3Qoc3ViX2FsbGNlbGxzX2RzaGVwLCBncm91cC5ieSA9ICJzdWJwb3BzIiwgaWRlbnRzID0gcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBmLCBzcGxpdC5ieSA9ICJDb25kaXRpb24iLCBuY29sID0gMSkrCiAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQogICAgIyByZXNjYWxpbmcgKG5vdCBmb3IgcGxvdHRpbmcgb25seSB0ZXN0aW5nKQogICAgaWYoIShwYXN0ZTAoZiwgIl9yZXNjIikgJWluJSBjb2xuYW1lcyhzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhKSkpewogICAgICBzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhWyxwYXN0ZTAoZiwgIl9yZXNjIildID0gc2NhbGVzOjpyZXNjYWxlKHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGFbLGZdLCB0byA9IGMoMCwgbWF4KHNjYWxlczo6cmVzY2FsZShzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhWyxmXSkpKSkKICAgIH0KICAgIGZvcihpIGluIDE6bmNvbChjb25kX21hdCkpewogICAgICB0ZXN0ID0gd2lsY294LnRlc3Qoc3ViX2FsbGNlbGxzX2RzaGVwQG1ldGEuZGF0YVtzdWJfYWxsY2VsbHNfZHNoZXAkc3VicG9wcz09cyAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Yl9hbGxjZWxsc19kc2hlcCRDb25kaXRpb249PWNvbmRfbWF0WzEsaV0scGFzdGUwKGYsICJfcmVzYyIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgIHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGFbc3ViX2FsbGNlbGxzX2RzaGVwJHN1YnBvcHM9PXMgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJfYWxsY2VsbHNfZHNoZXAkQ29uZGl0aW9uPT1jb25kX21hdFsyLGldLHBhc3RlMChmLCAiX3Jlc2MiKV0sIAogICAgICAgICAgICAgICAgICBleGFjdCA9IEYpCiAgICAgIGlkID0gcGFzdGUwKGNvbmRfbWF0WzEsaV0sICJfdl8iLCBjb25kX21hdFsyLGldKQogICAgICBwdmFsX2xpc3RbW3NdXVtbZl1dW1tpZF1dID0gdGVzdCRwLnZhbHVlCiAgICAgIGQgPSBtZWFuKHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGFbc3ViX2FsbGNlbGxzX2RzaGVwJHN1YnBvcHM9PXMgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJfYWxsY2VsbHNfZHNoZXAkQ29uZGl0aW9uPT1jb25kX21hdFsxLGldLHBhc3RlMChmLCAiX3Jlc2MiKV0pL21lYW4oc3ViX2FsbGNlbGxzX2RzaGVwQG1ldGEuZGF0YVtzdWJfYWxsY2VsbHNfZHNoZXAkc3VicG9wcz09cyAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Yl9hbGxjZWxsc19kc2hlcCRDb25kaXRpb249PWNvbmRfbWF0WzIsaV0scGFzdGUwKGYsICJfcmVzYyIpXSkKICAgICAgZGlmZl9saXN0W1tzXV1bW2ZdXVtbaWRdXSA9IGxvZzIoZCkKICAgIH0KICB9Cn0KCnB2YWxkZiA9IHJlc2hhcGUyOjptZWx0KHB2YWxfbGlzdClbLDQ6MV0KcHZhbGRmJGZkciA9IHAuYWRqdXN0KHB2YWxkZiR2YWx1ZSwgbWV0aG9kID0gImZkciIpCmRpZmZkZiA9IHJlc2hhcGUyOjptZWx0KGRpZmZfbGlzdClbLDQ6MV0KcHZhbGRmJGZjID0gZGlmZmRmJHZhbHVlCmBgYAoKQ2hlY2sgdG9wIGhpdHMKCmBgYHtyfQpwdmFsZGZfZmlsdCA9IHB2YWxkZltwdmFsZGYkZmRyPD0wLjA1LF0Kc2lnZmNfcGx0cyA9IGxpc3QoKQpmb3IoY2MgaW4gYygiaGVhbHRoeV92X2VtYm9saXNlZCIsICJoZWFsdGh5X3ZfcmVnZW5lcmF0aW5nIikpewogIHN1YmRmID0gcHZhbGRmX2ZpbHRbcHZhbGRmX2ZpbHQkTDM9PWNjLF0KICBzaWdmY19wbHRzW1tjY11dID0gbGlzdCgpCiAgZm9yKGN0IGluIHVuaXF1ZShwdmFsZGZfZmlsdCRMMSkpewogICAgc3Vic3ViZGYgPSBzdWJkZltzdWJkZiRMMT09Y3QsXQogICAgc3Vic3ViZGYgPSBzdWJzdWJkZltvcmRlcihzdWJzdWJkZiRmYywgZGVjcmVhc2luZyA9IEYpLF0KICAgIHN1YnN1YmRmJEwyID0gZmFjdG9yKHN1YnN1YmRmJEwyLCBsZXZlbHMgPSB1bmlxdWUoc3Vic3ViZGYkTDIpKQogICAgCiAgICBzaWdmY19wbHRzW1tjY11dW1tjdF1dID0gZ2dwbG90KHN1YnN1YmRmLCBhZXMoeCA9IEwyLCB5ID0gZmMpKSsKICAgICAgZ2VvbV9jb2woKSsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygtLjIsIC4yKSwgbGluZXR5cGUgPSAiZGFzaGVkIikrCiAgICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEpKQogIH0KfQpgYGAKCgojIyBDZWxsIHR5cGUgc2lnbmF0dXJlCkNhbGN1bGF0ZSBzaWduYXR1cmVzIGZvciBlYWNoIGNlbGwgdHlwZQoKYGBge3J9CnN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGEgPSBzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhWywxOjExOF0KCiMgZ2V0IHRvcCBtYXJrZXJzIGZvciBjZWxsIHR5cGVzCmN0dG9wID0gbGlzdCgpCnRvcG4gPSA1MApmb3IoaSBpbiB1bmlxdWUobWtfY3RfYWxsJHBlcmxpbmVhZ2UkY2x1c3RlcikpewogIHN1YmRmID0gbWtfY3RfYWxsJHBlcmxpbmVhZ2VbbWtfY3RfYWxsJHBlcmxpbmVhZ2UkY2x1c3Rlcj09aSAmIG1rX2N0X2FsbCRwZXJsaW5lYWdlJHBfdmFsX2Fkajw9MC4wNSxdCiAgY3R0b3BbW2ldXSA9IHN1YmRmW29yZGVyKHN1YmRmJGF2Z19sb2cyRkMsIGRlY3JlYXNpbmcgPSBUKSwiZ2VuZSJdWzE6dG9wbl0KICBjdHRvcCA9IGxhcHBseShjdHRvcCwgZnVuY3Rpb24oeCkgeFshaXMubmEoeCldKQp9CgojIGdldCBzaWduYXR1cmVzCnN1Yl9hbGxjZWxsc19kc2hlcCA9IEFkZE1vZHVsZVNjb3JlKHN1Yl9hbGxjZWxsc19kc2hlcCwgZmVhdHVyZXMgPSBjdHRvcCwgbmJpbiA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9IDEsIGN0cmwgPSA1MDAsIG5hbWUgPSAiY3Rfc2lnXyIpCmNvbF9zaWdzID0gZ3JlcGwoImN0X3NpZ18iLCBjb2xuYW1lcyhzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhKSkKY29sbmFtZXMoc3ViX2FsbGNlbGxzX2RzaGVwQG1ldGEuZGF0YSlbY29sX3NpZ3NdID0gcGFzdGUwKCJjdF9zaWdfIiwgbmFtZXMoY3R0b3ApKQpgYGAKCkxpc3QsIGZvciBlYWNoIGNlbGwgdHlwZSwgd2hpY2ggc2lnbmF0dXJlcyBjb3VsZCBtYWtlIHNlbnNlCgpgYGB7cn0KZmVhdHMgPSBjb2xuYW1lcyhzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhKVtzdGFydHNXaXRoKGNvbG5hbWVzKHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGEpLCAiY3Rfc2lnXyIpXQpzaWdfYXNzX2xpc3QgPSBsYXBwbHkodW5pcXVlKHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGEkc3VicG9wcyksIGZ1bmN0aW9uKHgpIGMoKSkKbmFtZXMoc2lnX2Fzc19saXN0KSA9IHVuaXF1ZShzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhJHN1YnBvcHMpCmZvcihjdCBpbiBuYW1lcyhzaWdfYXNzX2xpc3QpKXsKICBpZihncmVwbCgiTksgIiwgY3QpIHwgZ3JlcGwoIlRyZWciLCBjdCkgfCBncmVwbCgiSUxDIiwgY3QpIHwgCiAgICAgZ3JlcGwoIlQgY2VsbCIsIGN0KSB8IGdyZXBsKCJNQUlUIiwgY3QpIHwgZ3JlcGwoIlRSTSIsIGN0KSl7CiAgICBzaWdfYXNzX2xpc3RbW2N0XV0gPSBjKHNpZ19hc3NfbGlzdFtbY3RdXSwgZmVhdHNbZ3JlcGwoIklMQ3MiLCBmZWF0cykgfCBncmVwbCgiVGNlbGxzIiwgZmVhdHMpXSkKICB9IGVsc2UgaWYoZ3JlcGwoIkRDIiwgY3QpIHwgZ3JlcGwoIkt1cGZmZXIiLCBjdCkgfCBncmVwbCgiTW9ub2N5dGUiLCBjdCkgfCBncmVwbCgiTWFjcm9waGFnZSIsIGN0KSl7CiAgICBzaWdfYXNzX2xpc3RbW2N0XV0gPSBjKHNpZ19hc3NfbGlzdFtbY3RdXSwgZmVhdHNbZ3JlcGwoIk1QcyIsIGZlYXRzKSB8IGdyZXBsKCJEQyIsIGZlYXRzKV0pCiAgfSBlbHNlIGlmKGdyZXBsKCJIZXBhdG8iLCBjdCkpewogICAgc2lnX2Fzc19saXN0W1tjdF1dID0gYyhzaWdfYXNzX2xpc3RbW2N0XV0sICJDaXJyX2xpX0hlcGF0b2N5dGVzIikKICB9IGVsc2UgaWYoZ3JlcGwoIkNob2xhbmdpb2N5dGVzIiwgY3QpKXsKICAgIHNpZ19hc3NfbGlzdFtbY3RdXSA9IGMoc2lnX2Fzc19saXN0W1tjdF1dLCBmZWF0c1tncmVwbCgiQ2hvbGFuZ2lvY3l0ZXMiLCBmZWF0cykgXSkKICB9IGVsc2UgaWYoZ3JlcGwoIkIgY2VsbCIsIGN0KSB8IGdyZXBsKCJQbGFzbWEiLCBjdCkpewogICAgc2lnX2Fzc19saXN0W1tjdF1dID0gYyhzaWdfYXNzX2xpc3RbW2N0XV0sIGZlYXRzW2dyZXBsKCJCY2VsbHMiLCBmZWF0cyldKQogIH0gZWxzZSBpZihncmVwbCgiU3RlbGxhdGUiLCBjdCkpewogICAgc2lnX2Fzc19saXN0W1tjdF1dID0gYyhzaWdfYXNzX2xpc3RbW2N0XV0sIGZlYXRzW2dyZXBsKCJNZXNlbmNoeW1lIiwgZmVhdHMpIHwgZ3JlcGwoIk15b2ZpYnJvYmxhc3QiLCBmZWF0cyldKQogIH0gZWxzZSBpZihncmVwbCgiRUMiLCBjdCkgfCBncmVwbCgiZW5kb3RoZWxpYWwiLCBjdCkpewogICAgc2lnX2Fzc19saXN0W1tjdF1dID0gYyhzaWdfYXNzX2xpc3RbW2N0XV0sIGZlYXRzW2dyZXBsKCJFbmRvdGhlbGlhIiwgZmVhdHMpXSkKICB9Cn0KYGBgCgpQbG90IHNpZ25hdHVyZXMgZm9yIGdyb3VwcyBvZiBjZWxsIHR5cGVzCgpgYGB7cn0KY3RfdmFycyA9IGdyZXBsKCJjdF9zaWdfIiwgY29sbmFtZXMoc3ViX2FsbGNlbGxzX2RzaGVwQG1ldGEuZGF0YSkpCnBsb3RfZGYgPSBzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhWyxjKCJzdWJwb3BzIiwgIkNvbmRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG5hbWVzKHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGEpW2N0X3ZhcnNdKV0KcGxvdF9kZiA9IHJlc2hhcGUyOjptZWx0KHBsb3RfZGYpCgpwbG90X2N0X3NpZ3MgPSBsaXN0KCkKZm9yKGdyIGluIGMoIkt1cGZmZXIgY2VsbHMiLCAiQ0Q4IGFiLVQgY2VsbHMgMSIsICJFQyBub24tTFNFQyIsICJDaG9sYW5naW9jeXRlcyIpKXsKICBjdF91c2UgPSBuYW1lcyhzaWdfYXNzX2xpc3QpW3VubGlzdChsYXBwbHkoc2lnX2Fzc19saXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgbGVuZ3RoKGludGVyc2VjdCh4LHNpZ19hc3NfbGlzdFtbZ3JdXSkpPT1sZW5ndGgoeCkpKV0KICBzdWJfcGxvdF9kZiA9IHBsb3RfZGZbcGxvdF9kZiRzdWJwb3BzICVpbiUgY3RfdXNlICYgcGxvdF9kZiR2YXJpYWJsZSAlaW4lIHNpZ19hc3NfbGlzdFtbZ3JdXSxdCiAgc3ViX3Bsb3RfZGYkdmFyaWFibGUgPSBzdWJzdHIoc3ViX3Bsb3RfZGYkdmFyaWFibGUgLCA4LCAyMDApCiAgCiAgbWVhbl9kZiA9IHJlc2hhcGUyOjptZWx0KHRhcHBseShzdWJfcGxvdF9kZiR2YWx1ZSwgc3ViX3Bsb3RfZGYkdmFyaWFibGUsIG1lYW4pKQogIGNvbG5hbWVzKG1lYW5fZGYpWzFdID0gInZhcmlhYmxlIgogIAogIHBsb3RfY3Rfc2lnc1tbZ3JdXSA9IGdncGxvdChzdWJfcGxvdF9kZiwgYWVzKHggPSB2YWx1ZSwgeSA9IHN1YnBvcHMsIGZpbGwgPSBzdWJwb3BzKSkrCiAgICBmYWNldF93cmFwKH52YXJpYWJsZSwgbmNvbCA9IGxlbmd0aChtZWFuX2RmJHZhcmlhYmxlKSwgc2NhbGVzID0gImZyZWVfeCIpKwogICAgZ2VvbV92aW9saW4oc2l6ZSA9IDAuMikrCiAgICBnZW9tX3ZsaW5lKG1hcHBpbmcgPSBhZXMoeGludGVyY2VwdCA9IHZhbHVlKSwgZGF0YSA9IG1lYW5fZGYsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAwLjQpKwogICAgbGFicyh4ID0gIlNpZ25hdHVyZSBzY29yZSIsIHkgPSAiU3VicG9wdWxhdGlvbiIpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjYsIGNvbG91ciA9ICJibGFjayIpKQp9CmBgYAoKVGVzdGluZyBmb3Igc2lnbmlmaWNhbmNlIGFuZCBpbmRpdmlkdWFsIHBsb3R0aW5nCgpgYGB7cn0KY29uZF9tYXQgPSBjb21ibih1bmlxdWUoc3ViX2FsbGNlbGxzX2RzaGVwJENvbmRpdGlvbiksIDIpCnB2YWxfbGlzdCA9IGxpc3QoKQpkaWZmX2xpc3QgPSBsaXN0KCkKcGxvdHNfbGlzdCA9IGxpc3QoKQpmb3IocyBpbiBuYW1lcyhzaWdfYXNzX2xpc3QpKXsKICBwdmFsX2xpc3RbW3NdXSA9IGxpc3QoKQogIGRpZmZfbGlzdFtbc11dID0gbGlzdCgpCiAgcGxvdHNfbGlzdFtbc11dID0gbGlzdCgpCiAgZm9yKGYgaW4gc2lnX2Fzc19saXN0W1tzXV0pewogICAgcHZhbF9saXN0W1tzXV1bW2ZdXSA9IGxpc3QoKQogICAgZGlmZl9saXN0W1tzXV1bW2ZdXSA9IGxpc3QoKQogICAgcGxvdHNfbGlzdFtbc11dW1tmXV0gPSBWbG5QbG90KHN1Yl9hbGxjZWxsc19kc2hlcCwgZ3JvdXAuYnkgPSAic3VicG9wcyIsIGlkZW50cyA9IHMsIGZlYXR1cmVzID0gZiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGxpdC5ieSA9ICJDb25kaXRpb24iLCBuY29sID0gMSkrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCiAgICAjIHJlc2NhbGluZyAobm90IGZvciBwbG90dGluZyBvbmx5IHRlc3RpbmcpCiAgICBpZighKHBhc3RlMChmLCAiX3Jlc2MiKSAlaW4lIGNvbG5hbWVzKHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGEpKSl7CiAgICAgIHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGFbLHBhc3RlMChmLCAiX3Jlc2MiKV0gPSBzY2FsZXM6OnJlc2NhbGUoc3ViX2FsbGNlbGxzX2RzaGVwQG1ldGEuZGF0YVssZl0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gYygwLCBtYXgoc2NhbGVzOjpyZXNjYWxlKHN1Yl9hbGxjZWxsc19kc2hlcEBtZXRhLmRhdGFbLGZdKSkpKQogICAgfQogICAgZm9yKGkgaW4gMTpuY29sKGNvbmRfbWF0KSl7CiAgICAgIHRlc3QgPSB3aWxjb3gudGVzdChzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhW3N1Yl9hbGxjZWxsc19kc2hlcCRzdWJwb3BzPT1zICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViX2FsbGNlbGxzX2RzaGVwJENvbmRpdGlvbj09Y29uZF9tYXRbMSxpXSxwYXN0ZTAoZiwgIl9yZXNjIildLAogICAgICAgICAgICAgICAgICAgICAgICAgc3ViX2FsbGNlbGxzX2RzaGVwQG1ldGEuZGF0YVtzdWJfYWxsY2VsbHNfZHNoZXAkc3VicG9wcz09cyAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Yl9hbGxjZWxsc19kc2hlcCRDb25kaXRpb249PWNvbmRfbWF0WzIsaV0scGFzdGUwKGYsICJfcmVzYyIpXSwgCiAgICAgICAgICAgICAgICAgIGV4YWN0ID0gRikKICAgICAgaWQgPSBwYXN0ZTAoY29uZF9tYXRbMSxpXSwgIl92XyIsIGNvbmRfbWF0WzIsaV0pCiAgICAgIHB2YWxfbGlzdFtbc11dW1tmXV1bW2lkXV0gPSB0ZXN0JHAudmFsdWUKICAgICAgZCA9IG1lYW4oc3ViX2FsbGNlbGxzX2RzaGVwQG1ldGEuZGF0YVtzdWJfYWxsY2VsbHNfZHNoZXAkc3VicG9wcz09cyAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Yl9hbGxjZWxsc19kc2hlcCRDb25kaXRpb249PWNvbmRfbWF0WzEsaV0scGFzdGUwKGYsICJfcmVzYyIpXSkvbWVhbihzdWJfYWxsY2VsbHNfZHNoZXBAbWV0YS5kYXRhW3N1Yl9hbGxjZWxsc19kc2hlcCRzdWJwb3BzPT1zICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViX2FsbGNlbGxzX2RzaGVwJENvbmRpdGlvbj09Y29uZF9tYXRbMixpXSxwYXN0ZTAoZiwgIl9yZXNjIildKQogICAgICBkaWZmX2xpc3RbW3NdXVtbZl1dW1tpZF1dID0gbG9nMihkKQogICAgfQogIH0KfQoKcHZhbGRmX2N0ID0gcmVzaGFwZTI6Om1lbHQocHZhbF9saXN0KVssNDoxXQpwdmFsZGZfY3QkZmRyID0gcC5hZGp1c3QocHZhbGRmX2N0JHZhbHVlLCBtZXRob2QgPSAiZmRyIikKZGlmZmRmX2N0ID0gcmVzaGFwZTI6Om1lbHQoZGlmZl9saXN0KVssNDoxXQpwdmFsZGZfY3QkZmMgPSBkaWZmZGZfY3QkdmFsdWUKYGBgCgoKIyMgU3BlY2lmaWMgZGF0YXNldHMKQ2FsY3VsYXRlIGNpcnJob3RpYyBzaWduYXR1cmVzCgpgYGB7cn0Kc2lnc19lbmRvX2NvbmQgPSBjaXJfc2lnc2FsbFtjKCJFbmRvdGhlbGlhICgxKSIsIkVuZG90aGVsaWEgKDIpIiwiRW5kb3RoZWxpYSAoMykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVuZG90aGVsaWEgKDUpIiwiRW5kb3RoZWxpYSAoNikiLCAiRW5kb3RoZWxpYSAoNykiKV0KZW5kX2NlbGxzQG1ldGEuZGF0YSA9IGVuZF9jZWxsc0BtZXRhLmRhdGFbLCFncmVwbCgiY2lycl9jb25kXyIsIGNvbG5hbWVzKGVuZF9jZWxsc0BtZXRhLmRhdGEpKV0KZW5kX2NlbGxzID0gQWRkTW9kdWxlU2NvcmUoZW5kX2NlbGxzLCBmZWF0dXJlcyA9IHNpZ3NfZW5kb19jb25kLCBuYmluID0gMzAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzZWVkID0gMSwgY3RybCA9IDUwMCwgbmFtZSA9ICJjaXJyX2NvbmRfIikKY29sX3NpZ3MgPSBncmVwbCgiY2lycl9jb25kXyIsIGNvbG5hbWVzKGVuZF9jZWxsc0BtZXRhLmRhdGEpKQpjb2xuYW1lcyhlbmRfY2VsbHNAbWV0YS5kYXRhKVtjb2xfc2lnc10gPSBwYXN0ZTAoImNpcnJfY29uZF8iLCBuYW1lcyhzaWdzX2VuZG9fY29uZCkpCmNvbG5hbWVzKGVuZF9jZWxsc0BtZXRhLmRhdGEpID0gZ3N1YigiICgiLCAiXyIsIGNvbG5hbWVzKGVuZF9jZWxsc0BtZXRhLmRhdGEpLCBmaXhlZCA9IFQpCmNvbG5hbWVzKGVuZF9jZWxsc0BtZXRhLmRhdGEpID0gZ3N1YigiKSIsICIiLCBjb2xuYW1lcyhlbmRfY2VsbHNAbWV0YS5kYXRhKSwgZml4ZWQgPSBUKQoKc2lnc19tb25vX2NvbmQgPSBjaXJfc2lnc2FsbFtjKCJNUHMgKDEpIiwiTVBzICgyKSIsIk1QcyAoMykiLCJNUHMgKDQpIiwiTVBzICg1KSIsIk1QcyAoNikiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1QcyAoNykiLCJNUHMgKDgpIiwiTVBzICg5KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ3ljbGluZyBNUHMgKDEpIiwiQ3ljbGluZyBNUHMgKDMpIildCm1vbl9jZWxsc0BtZXRhLmRhdGEgPSBtb25fY2VsbHNAbWV0YS5kYXRhWywhZ3JlcGwoImNpcnJfY29uZF8iLCBjb2xuYW1lcyhtb25fY2VsbHNAbWV0YS5kYXRhKSldCm1vbl9jZWxscyA9IEFkZE1vZHVsZVNjb3JlKG1vbl9jZWxscywgZmVhdHVyZXMgPSBzaWdzX21vbm9fY29uZCwgbmJpbiA9IDMwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9IDEsIGN0cmwgPSA1MDAsIG5hbWUgPSAiY2lycl9jb25kXyIpCmNvbF9zaWdzID0gZ3JlcGwoImNpcnJfY29uZF8iLCBjb2xuYW1lcyhtb25fY2VsbHNAbWV0YS5kYXRhKSkKY29sbmFtZXMobW9uX2NlbGxzQG1ldGEuZGF0YSlbY29sX3NpZ3NdID0gcGFzdGUwKCJjaXJyX2NvbmRfIiwgbmFtZXMoc2lnc19tb25vX2NvbmQpKQpjb2xuYW1lcyhtb25fY2VsbHNAbWV0YS5kYXRhKSA9IGdzdWIoIiAoIiwgIl8iLCBjb2xuYW1lcyhtb25fY2VsbHNAbWV0YS5kYXRhKSwgZml4ZWQgPSBUKQpjb2xuYW1lcyhtb25fY2VsbHNAbWV0YS5kYXRhKSA9IGdzdWIoIikiLCAiIiwgY29sbmFtZXMobW9uX2NlbGxzQG1ldGEuZGF0YSksIGZpeGVkID0gVCkKCnNpZ3NfaGVwYV9jb25kID0gY2lyX3NpZ3NhbGxbYygiSGVwYXRvY3l0ZXMiKV0KZHNfaGVwX3NyYXRAbWV0YS5kYXRhID0gZHNfaGVwX3NyYXRAbWV0YS5kYXRhWywhZ3JlcGwoImNpcnJfY29uZF8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhkc19oZXBfc3JhdEBtZXRhLmRhdGEpKV0KZHNfaGVwX3NyYXQgPSBBZGRNb2R1bGVTY29yZShkc19oZXBfc3JhdCwgZmVhdHVyZXMgPSBzaWdzX2hlcGFfY29uZCwgbmJpbiA9IDMwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWVkID0gMSwgY3RybCA9IDUwMCwgbmFtZSA9ICJjaXJyX2NvbmRfIikKY29sX3NpZ3MgPSBncmVwbCgiY2lycl9jb25kXyIsIGNvbG5hbWVzKGRzX2hlcF9zcmF0QG1ldGEuZGF0YSkpCmNvbG5hbWVzKGRzX2hlcF9zcmF0QG1ldGEuZGF0YSlbY29sX3NpZ3NdID0gcGFzdGUwKCJjaXJyX2NvbmRfIiwgbmFtZXMoc2lnc19oZXBhX2NvbmQpKQpgYGAKCkNhbGN1bGF0ZSBjZWxsIHR5cGUgc2lnbmF0dXJlcwoKYGBge3J9CnNpZ3NfZW5kb19jb25kID0gY3R0b3BbYygiRW5kb3RoZWxpYSAoMSkiLCJFbmRvdGhlbGlhICgyKSIsIkVuZG90aGVsaWEgKDMpIiwiRW5kb3RoZWxpYSAoNCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgIkVuZG90aGVsaWEgKDUpIiwiRW5kb3RoZWxpYSAoNikiLCAiRW5kb3RoZWxpYSAoNykiKV0KZW5kX2NlbGxzQG1ldGEuZGF0YSA9IGVuZF9jZWxsc0BtZXRhLmRhdGFbLCFncmVwbCgiY2lycl9jdF8iLCBjb2xuYW1lcyhlbmRfY2VsbHNAbWV0YS5kYXRhKSldCmVuZF9jZWxscyA9IEFkZE1vZHVsZVNjb3JlKGVuZF9jZWxscywgZmVhdHVyZXMgPSBzaWdzX2VuZG9fY29uZCwgbmJpbiA9IDMwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9IDEsIGN0cmwgPSA1MDAsIG5hbWUgPSAiY2lycl9jdF8iKQpjb2xfc2lncyA9IGdyZXBsKCJjaXJyX2N0XyIsIGNvbG5hbWVzKGVuZF9jZWxsc0BtZXRhLmRhdGEpKQpjb2xuYW1lcyhlbmRfY2VsbHNAbWV0YS5kYXRhKVtjb2xfc2lnc10gPSBwYXN0ZTAoImNpcnJfY3RfIiwgbmFtZXMoc2lnc19lbmRvX2NvbmQpKQpjb2xuYW1lcyhlbmRfY2VsbHNAbWV0YS5kYXRhKSA9IGdzdWIoIiAoIiwgIl8iLCBjb2xuYW1lcyhlbmRfY2VsbHNAbWV0YS5kYXRhKSwgZml4ZWQgPSBUKQpjb2xuYW1lcyhlbmRfY2VsbHNAbWV0YS5kYXRhKSA9IGdzdWIoIikiLCAiIiwgY29sbmFtZXMoZW5kX2NlbGxzQG1ldGEuZGF0YSksIGZpeGVkID0gVCkKCnNpZ3NfbW9ub19jb25kID0gY3R0b3BbYygiTVBzICgxKSIsIk1QcyAoMikiLCJNUHMgKDMpIiwiTVBzICg0KSIsIk1QcyAoNSkiLCJNUHMgKDYpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJNUHMgKDcpIiwiTVBzICg4KSIsIk1QcyAoOSkiLCAiQ3ljbGluZyBNUHMgKDEpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJDeWNsaW5nIE1QcyAoMikiLCJDeWNsaW5nIE1QcyAoMykiLCJDeWNsaW5nIE1QcyAoNCkiKV0KbW9uX2NlbGxzQG1ldGEuZGF0YSA9IG1vbl9jZWxsc0BtZXRhLmRhdGFbLCFncmVwbCgiY2lycl9jdF8iLCBjb2xuYW1lcyhtb25fY2VsbHNAbWV0YS5kYXRhKSldCm1vbl9jZWxscyA9IEFkZE1vZHVsZVNjb3JlKG1vbl9jZWxscywgZmVhdHVyZXMgPSBzaWdzX21vbm9fY29uZCwgbmJpbiA9IDMwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9IDEsIGN0cmwgPSA1MDAsIG5hbWUgPSAiY2lycl9jdF8iKQpjb2xfc2lncyA9IGdyZXBsKCJjaXJyX2N0XyIsIGNvbG5hbWVzKG1vbl9jZWxsc0BtZXRhLmRhdGEpKQpjb2xuYW1lcyhtb25fY2VsbHNAbWV0YS5kYXRhKVtjb2xfc2lnc10gPSBwYXN0ZTAoImNpcnJfY3RfIiwgbmFtZXMoc2lnc19tb25vX2NvbmQpKQpjb2xuYW1lcyhtb25fY2VsbHNAbWV0YS5kYXRhKSA9IGdzdWIoIiAoIiwgIl8iLCBjb2xuYW1lcyhtb25fY2VsbHNAbWV0YS5kYXRhKSwgZml4ZWQgPSBUKQpjb2xuYW1lcyhtb25fY2VsbHNAbWV0YS5kYXRhKSA9IGdzdWIoIikiLCAiIiwgY29sbmFtZXMobW9uX2NlbGxzQG1ldGEuZGF0YSksIGZpeGVkID0gVCkKCnNpZ3NfaGVwYV9jb25kID0gY3R0b3BbYygiSGVwYXRvY3l0ZXMiKV0KZHNfaGVwX3NyYXRAbWV0YS5kYXRhID0gZHNfaGVwX3NyYXRAbWV0YS5kYXRhWywhZ3JlcGwoImNpcnJfY3RfIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMoZHNfaGVwX3NyYXRAbWV0YS5kYXRhKSldCmRzX2hlcF9zcmF0ID0gQWRkTW9kdWxlU2NvcmUoZHNfaGVwX3NyYXQsIGZlYXR1cmVzID0gc2lnc19oZXBhX2NvbmQsIG5iaW4gPSAzMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9IDEsIGN0cmwgPSA1MDAsIG5hbWUgPSAiY2lycl9jdF8iKQpjb2xfc2lncyA9IGdyZXBsKCJjaXJyX2N0XyIsIGNvbG5hbWVzKGRzX2hlcF9zcmF0QG1ldGEuZGF0YSkpCmNvbG5hbWVzKGRzX2hlcF9zcmF0QG1ldGEuZGF0YSlbY29sX3NpZ3NdID0gcGFzdGUwKCJjaXJyX2N0XyIsIG5hbWVzKHNpZ3NfaGVwYV9jb25kKSkKYGBgCgpQbG90IHNpZ25hdHVyZXMgLSBlbmRvdGhlbGlhbAoKYGBge3IsIGZpZy5oZWlnaHQgPSAxNSwgZmlnLndpZHRoID0gOH0KVmxuUGxvdChlbmRfY2VsbHMsIGdyb3VwLmJ5ID0gImVuZG9fc2ltcCIsIAogICAgICAgIGZlYXR1cmVzID0gYygiY2lycl9jb25kX0VuZG90aGVsaWFfMSIsICJjaXJyX2NvbmRfRW5kb3RoZWxpYV8yIiwKICAgICAgICAgICAgICAgICAgICAgImNpcnJfY29uZF9FbmRvdGhlbGlhXzMiLCAiY2lycl9jb25kX0VuZG90aGVsaWFfNSIsCiAgICAgICAgICAgICAgICAgICAgICJjaXJyX2NvbmRfRW5kb3RoZWxpYV82IiwgImNpcnJfY29uZF9FbmRvdGhlbGlhXzciKSwgCiAgICAgICAgc3BsaXQuYnkgPSAiQ29uZGl0aW9uIiwgbmNvbCA9IDEpClZsblBsb3QoZW5kX2NlbGxzLCBncm91cC5ieSA9ICJlbmRvX3NpbXAiLCAKICAgICAgICBmZWF0dXJlcyA9IGMoImNpcnJfY3RfRW5kb3RoZWxpYV8xIiwgImNpcnJfY3RfRW5kb3RoZWxpYV8yIiwgImNpcnJfY3RfRW5kb3RoZWxpYV8zIiwKICAgICAgICAgICAgICAgICAgICAgImNpcnJfY3RfRW5kb3RoZWxpYV80IiwgImNpcnJfY3RfRW5kb3RoZWxpYV81IiwgImNpcnJfY3RfRW5kb3RoZWxpYV82IiwKICAgICAgICAgICAgICAgICAgICAgImNpcnJfY3RfRW5kb3RoZWxpYV83IiksIAogICAgICAgIHNwbGl0LmJ5ID0gIkNvbmRpdGlvbiIsIG5jb2wgPSAxKQpgYGAKClBsb3Qgc2lnbmF0dXJlcyAtIG1vbm9jeXRlcwoKYGBge3IsIGZpZy5oZWlnaHQgPSAzMCwgZmlnLndpZHRoID0gMTB9ClZsblBsb3QobW9uX2NlbGxzLCBncm91cC5ieSA9ICJtb25vX2Fubm90IiwgCiAgICAgICAgZmVhdHVyZXMgPSBjKCJjaXJyX2NvbmRfTVBzXzEiLCAiY2lycl9jb25kX01Qc18yIiwgImNpcnJfY29uZF9NUHNfMyIsICJjaXJyX2NvbmRfTVBzXzQiLAogICAgICAgICAgICAgICAgICAgICAiY2lycl9jb25kX01Qc181IiwgImNpcnJfY29uZF9NUHNfNiIsImNpcnJfY29uZF9NUHNfNyIsICJjaXJyX2NvbmRfTVBzXzgiLAogICAgICAgICAgICAgICAgICAgICAiY2lycl9jb25kX01Qc185IiwgImNpcnJfY29uZF9DeWNsaW5nIE1Qc18xIiwgImNpcnJfY29uZF9DeWNsaW5nIE1Qc18zIiksIAogICAgICAgIHNwbGl0LmJ5ID0gIkNvbmRpdGlvbiIsIG5jb2wgPSAxKQpWbG5QbG90KG1vbl9jZWxscywgZ3JvdXAuYnkgPSAibW9ub19hbm5vdCIsIAogICAgICAgIGZlYXR1cmVzID0gYygiY2lycl9jdF9NUHNfMSIsICJjaXJyX2N0X01Qc18yIiwgImNpcnJfY3RfTVBzXzMiLCAiY2lycl9jdF9NUHNfNCIsCiAgICAgICAgICAgICAgICAgICAgICJjaXJyX2N0X01Qc181IiwgImNpcnJfY3RfTVBzXzYiLCJjaXJyX2N0X01Qc183IiwgImNpcnJfY3RfTVBzXzgiLAogICAgICAgICAgICAgICAgICAgICAiY2lycl9jdF9NUHNfOSIsICJjaXJyX2N0X0N5Y2xpbmcgTVBzXzEiLCAiY2lycl9jdF9DeWNsaW5nIE1Qc18yIiwKICAgICAgICAgICAgICAgICAgICAgImNpcnJfY3RfQ3ljbGluZyBNUHNfMyIsICJjaXJyX2N0X0N5Y2xpbmcgTVBzXzQiKSwgCiAgICAgICAgc3BsaXQuYnkgPSAiQ29uZGl0aW9uIiwgbmNvbCA9IDEpCmBgYAoKUGxvdCBzaWduYXR1cmVzIC0gaGVwYXRvY3l0ZXMKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gNX0KVmxuUGxvdChkc19oZXBfc3JhdCwgZ3JvdXAuYnkgPSAic3VicG9wcyIsIGZlYXR1cmVzID0gYygiY2lycl9jb25kX0hlcGF0b2N5dGVzIiksIAogICAgICAgIHNwbGl0LmJ5ID0gIkNvbmRpdGlvbiIsIG5jb2wgPSAxKQpWbG5QbG90KGRzX2hlcF9zcmF0LCBncm91cC5ieSA9ICJzdWJwb3BzIiwgZmVhdHVyZXMgPSBjKCJjaXJyX2N0X0hlcGF0b2N5dGVzIiksIAogICAgICAgIHNwbGl0LmJ5ID0gIkNvbmRpdGlvbiIsIG5jb2wgPSAxKQpgYGAKCgoKYGBge3IsIGZpZy5oZWlnaHQ9MS41LCBmaWcud2lkdGg9NX0KY2lycl9jdCA9IGdyZXBsKCJjaXJyX2N0IiwgY29sbmFtZXMobW9uX2NlbGxzQG1ldGEuZGF0YSkpCnBsb3RfZGYgPSBtb25fY2VsbHNAbWV0YS5kYXRhWyxjaXJyX2N0IHwgY29sbmFtZXMobW9uX2NlbGxzQG1ldGEuZGF0YSkgJWluJSBjKCJDb25kaXRpb24iLCAibW9ub19hbm5vdCIpXQpwbG90X2RmJG1vbm9fYW5ub3QgPSBnc3ViKCIgKCIsICJcbigiLCBwbG90X2RmJG1vbm9fYW5ub3QsIGZpeGVkID0gVCkKCnNhdmVSRFMocGxvdF9kZiwgZmlsZSA9ICJyZXN1bHRzL2NpcnJob3Npcy9tb25vX2NpcnJfY3Rfc2lnbmF0dXJlcy5SRFMiKQoKY2lycl9jdCA9IGdyZXBsKCJjaXJyX2N0IiwgY29sbmFtZXMoZW5kX2NlbGxzQG1ldGEuZGF0YSkpCnBsb3RfZGYgPSBlbmRfY2VsbHNAbWV0YS5kYXRhWyxjaXJyX2N0IHwgY29sbmFtZXMoZW5kX2NlbGxzQG1ldGEuZGF0YSkgJWluJSBjKCJDb25kaXRpb24iLCAiZW5kb19zaW1wIildCnBsb3RfZGYkZW5kb19zaW1wID0gZ3N1YigiICgiLCAiXG4oIiwgcGxvdF9kZiRlbmRvX3NpbXAsIGZpeGVkID0gVCkKCnNhdmVSRFMocGxvdF9kZiwgZmlsZSA9ICJyZXN1bHRzL2NpcnJob3Npcy9lbmRvX2NpcnJfY3Rfc2lnbmF0dXJlcy5SRFMiKQoKcGxvdF9kZjIgPSByZXNoYXBlMjo6bWVsdChwbG90X2RmKQpnZ3Bsb3QocGxvdF9kZjJbcGxvdF9kZjIkdmFyaWFibGUgJWluJSBjKCJjaXJyX2N0X0VuZG90aGVsaWFfNiIsImNpcnJfY3RfRW5kb3RoZWxpYV83IiksXSwgCiAgICAgICBhZXMoeCA9IGVuZG9fc2ltcCwgeSA9IHZhbHVlLCBmaWxsID0gQ29uZGl0aW9uKSkrCiAgZmFjZXRfZ3JpZCh2YXJpYWJsZX5lbmRvX3NpbXAsIHNjYWxlcyA9ICJmcmVlIikrCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAiY291bnQiKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siLCBmaWxsID0gTkEpLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuMDQ4LCAwLjg2NSksCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjMsICJjbSIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNykpCmBgYAoKCgojIyBEZXZlbG9wbWVudCBzaWduYXR1cmUKR2V0IHRvcCAxMDAgbWFya2VycwoKYGBge3J9CmdncGxvdChiYmIsIGFlcyh4ID0gdFNORV8xLCB5ID0gdFNORV8yLCBjb2xvdXIgPSBhcy5jaGFyYWN0ZXIoaWRlbnQpKSkrCiAgZ2VvbV9wb2ludCgpCgpkZV9hbGwgPSBwcmVzdG86OndpbGNveGF1Yyhjb3VudHMsIGJiYiRpZGVudCkKCnRvcF9kZSA9IGRlX2FsbCAlPiUKICBncm91cF9ieShncm91cCkgJT4lCiAgdG9wX24od3QgPSBsb2dGQywgbiA9IDEwMCkKdG9wX2RlID0gdGFwcGx5KHRvcF9kZSRmZWF0dXJlLCB0b3BfZGUkZ3JvdXAsIGMpCmBgYAoKQ2FsY3VsYXRlIGdlbmUgbW9kdWxlcyBmb3IgZG93bnNhbXBsZWQgaGVwYXRvY3l0ZXMKCmBgYHtyfQpkc19oZXBfc3JhdEBtZXRhLmRhdGEgPSBkc19oZXBfc3JhdEBtZXRhLmRhdGFbLCFncmVwbCgiY2lycl9mZXRhbF8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhkc19oZXBfc3JhdEBtZXRhLmRhdGEpKV0KZHNfaGVwX3NyYXQgPSBBZGRNb2R1bGVTY29yZShkc19oZXBfc3JhdCwgZmVhdHVyZXMgPSB0b3BfZGUsIG5iaW4gPSAzMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9IDEsIGN0cmwgPSA1MDAsIG5hbWUgPSAiY2lycl9mZXRhbF8iLCBhc3NheSA9ICJTQ1QiKQpjb2xfc2lncyA9IGdyZXBsKCJjaXJyX2ZldGFsXyIsIGNvbG5hbWVzKGRzX2hlcF9zcmF0QG1ldGEuZGF0YSkpCmNvbG5hbWVzKGRzX2hlcF9zcmF0QG1ldGEuZGF0YSlbY29sX3NpZ3NdID0gcGFzdGUwKCJjaXJyX2ZldGFsXyIsIG5hbWVzKHRvcF9kZSkpCmBgYAoKUGxvdCBzaWduYXR1cmVzCgpgYGB7ciwgZmlnLmhlaWdodD0xOCwgZmlnLndpZHRoPTN9ClZsblBsb3QoZHNfaGVwX3NyYXQsIGdyb3VwLmJ5ID0gInN1YnBvcHMiLCAKICAgICAgICBmZWF0dXJlcyA9IGMoImNpcnJfZmV0YWxfMSIsImNpcnJfZmV0YWxfMiIsImNpcnJfZmV0YWxfMyIsImNpcnJfZmV0YWxfNCIsCiAgICAgICAgICAgICAgICAgICAgICJjaXJyX2ZldGFsXzUiLCJjaXJyX2ZldGFsXzYiLCAiY2lycl9mZXRhbF83IiksIAogICAgICAgIHNwbGl0LmJ5ID0gIkNvbmRpdGlvbiIsIG5jb2wgPSAxKQpgYGAKClBsb3QgMkQgZGVuc2l0eQoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0zfQpnZ3Bsb3QoZHNfaGVwX3NyYXRAbWV0YS5kYXRhLCBhZXMoeCA9IGNpcnJfZmV0YWxfMywgeSA9IGNpcnJfZmV0YWxfNiwgY29sb3VyID0gQ29uZGl0aW9uKSkrCiAgZmFjZXRfd3JhcCh+c3VicG9wcykrCiAgZ2VvbV9kZW5zaXR5XzJkKCkrCiAgdGhlbWVfY2xhc3NpYygpKwogIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEpCmBgYAoKUGxvdCBkZW5zaXR5IG9mIGVhY2ggdmFyaWFibGUKCmBgYHtyLCBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpwbHRfYWR1bHQgPSBnZ3Bsb3QoZHNfaGVwX3NyYXRAbWV0YS5kYXRhLCBhZXMoeCA9IGNpcnJfZmV0YWxfMywgY29sb3VyID0gQ29uZGl0aW9uKSkrCiAgZmFjZXRfd3JhcCh+c3VicG9wcykrCiAgZ2VvbV9kZW5zaXR5KCkrCiAgdGhlbWVfY2xhc3NpYygpKwogIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zLCAiY20iKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnBsdF9mZXRhbCA9IGdncGxvdChkc19oZXBfc3JhdEBtZXRhLmRhdGEsIGFlcyh4ID0gY2lycl9mZXRhbF82LCBjb2xvdXIgPSBDb25kaXRpb24pKSsKICBmYWNldF93cmFwKH5zdWJwb3BzKSsKICBnZW9tX2RlbnNpdHkoKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYuNSksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjMsICJjbSIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYuNSksCiAgICAgICAgbGVnZW5kLm1hcmdpbiA9IG1hcmdpbigwLDAsMCwwKSwKICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IG1hcmdpbigwLDAsMCwwKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCnBsdF9hZHVsdC9wbHRfZmV0YWwKYGBgCgpQbG90IG1lZGlhbiBhbmQgcXVhcnRpbGVzIGluIDJECgpgYGB7cn0KbWVhbl9hZHVsdCA9IHRhcHBseShkc19oZXBfc3JhdEBtZXRhLmRhdGEkY2lycl9mZXRhbF8zLAogICAgICAgICAgICAgICAgICAgIHBhc3RlMChkc19oZXBfc3JhdEBtZXRhLmRhdGEkQ29uZGl0aW9uLCAiLi4iLCBkc19oZXBfc3JhdEBtZXRhLmRhdGEkc3VicG9wcyksCiAgICAgICAgICAgICAgICAgICAgbWVkaWFuX2hpbG93LCBjb25mLmludD0uNSkKc3VtbV9hZHVsdCA9IFJlZHVjZShyYmluZCwgbWVhbl9hZHVsdCkKc3VtbV9hZHVsdCRpZCA9IG5hbWVzKG1lYW5fYWR1bHQpCnN1bW1fYWR1bHQkY29uZCA9IHVubGlzdChsYXBwbHkoc3Ryc3BsaXQoc3VtbV9hZHVsdCRpZCwgIi4uIiwgZml4ZWQgPSBUKSwgZnVuY3Rpb24oeCkgeFsxXSkpCnN1bW1fYWR1bHQkY3QgPSB1bmxpc3QobGFwcGx5KHN0cnNwbGl0KHN1bW1fYWR1bHQkaWQsICIuLiIsIGZpeGVkID0gVCksIGZ1bmN0aW9uKHgpIHhbMl0pKQoKbWVhbl9mZXRhbCA9IHRhcHBseShkc19oZXBfc3JhdEBtZXRhLmRhdGEkY2lycl9mZXRhbF82LAogICAgICAgICAgICAgICAgICAgIHBhc3RlMChkc19oZXBfc3JhdEBtZXRhLmRhdGEkQ29uZGl0aW9uLCAiLi4iLCBkc19oZXBfc3JhdEBtZXRhLmRhdGEkc3VicG9wcyksCiAgICAgICAgICAgICAgICAgICAgbWVkaWFuX2hpbG93LGNvbmYuaW50PS41KQpzdW1tX2ZldGFsID0gUmVkdWNlKHJiaW5kLCBtZWFuX2ZldGFsKQpzdW1tX2ZldGFsJGlkID0gbmFtZXMobWVhbl9mZXRhbCkKc3VtbV9mZXRhbCRjb25kID0gdW5saXN0KGxhcHBseShzdHJzcGxpdChzdW1tX2ZldGFsJGlkLCAiLi4iLCBmaXhlZCA9IFQpLCBmdW5jdGlvbih4KSB4WzFdKSkKc3VtbV9mZXRhbCRjdCA9IHVubGlzdChsYXBwbHkoc3Ryc3BsaXQoc3VtbV9mZXRhbCRpZCwgIi4uIiwgZml4ZWQgPSBUKSwgZnVuY3Rpb24oeCkgeFsyXSkpCgpwbG90X2RmID0gbWVyZ2Uoc3VtbV9mZXRhbCwgc3VtbV9hZHVsdCwgYnkgPSAiaWQiKQpwbG90X2RmID0gcGxvdF9kZlssYygxOjQsNzo5LDU6NildCmNvbG5hbWVzKHBsb3RfZGYpID0gYygiaWQiLCAiZmV0YWxfbWVhbiIsICJmZXRhbF9taW4iLCAiZmV0YWxfbWF4IiwKICAgICAgICAgICAgICAgICAgICAgICJhZHVsdF9tZWFuIiwgImFkdWx0X21pbiIsICJhZHVsdF9tYXgiLCJjb25kIiwgInN1YnBvcHMiKQoKZ2dwbG90KCkrCiAgZmFjZXRfd3JhcCh+c3VicG9wcykrCiAgZ2VvbV9kZW5zaXR5XzJkKGRhdGEgPSBkc19oZXBfc3JhdEBtZXRhLmRhdGEsIG1hcHBpbmcgPSBhZXMoeCA9IGNpcnJfZmV0YWxfMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGNpcnJfZmV0YWxfNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gQ29uZGl0aW9uKSkrCiAgZ2VvbV9wb2ludChkYXRhID0gcGxvdF9kZiwgbWFwcGluZyA9IGFlcyh4ID0gYWR1bHRfbWVhbiwgeSA9IGZldGFsX21lYW4sIGNvbG91ciA9IGNvbmQpLAogICAgICAgICAgICAgICAgIHNpemUgPSAzKSArIAogIGdlb21fZXJyb3JiYXIoZGF0YSA9IHBsb3RfZGYsIG1hcHBpbmcgPSBhZXMoeCA9IGFkdWx0X21lYW4sIHkgPSBmZXRhbF9tZWFuLCBjb2xvdXIgPSBjb25kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbiA9IGZldGFsX21pbiwgeW1heCA9IGZldGFsX21heCksCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDMpICsgCiAgZ2VvbV9lcnJvcmJhcmgoZGF0YSA9IHBsb3RfZGYsIG1hcHBpbmcgPSBhZXMoeCA9IGFkdWx0X21lYW4sIHkgPSBmZXRhbF9tZWFuLCBjb2xvdXIgPSBjb25kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhtaW4gPSBhZHVsdF9taW4sIHhtYXggPSBhZHVsdF9tYXgpLAogICAgICAgICAgICAgICAgIHNpemUgPSAzKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxKQpgYGAKClNhdmUgZG93bnNhbXBsZWQgaGVwIHdpdGggc2NvcmVzCgpgYGB7cn0Kc2F2ZVJEUyhkc19oZXBfc3JhdCwgZmlsZSA9ICJyZXN1bHRzL2NpcnJob3Npcy9kc19oZXBfc3JhdF9zY29yZWREZXYuUkRTIikKc2NvcmVzX2RmID0gZHNfaGVwX3NyYXRAbWV0YS5kYXRhWyxjKDE6MjMsMzMsMzQsNDk6NTUsNzI6NzgpXQpzYXZlUkRTKHNjb3Jlc19kZiwgZmlsZSA9ICJyZXN1bHRzL2NpcnJob3Npcy9kc19oZXBfc2NvcmVkRGV2X2RmLlJEUyIpCmBgYAoKCgo=